避免在循环中重复计算数组长度,应缓存 arr.length;去重优先用 Set;防抖节流需按场景选用,避免滥用;优先优化 DOM 访问和内存泄漏,再考虑 JS 执行性能。
常见错误是把 arr.length 直接写在 for 循环条件里,尤其当数组很大或 length 被代理/访问器劫持时,每次迭代都触发 getter,开销明显。
const len = arr.length; for (let i = 0; i
HTMLCollection 或带 getter 的类数组对象,必须手动缓存for...of,它不依赖 length,且语义清晰每次读写 offsetTop、clientWidth 或修改 style 属性,都可能触发强制同步布局(forced synchronous layout),性能杀手。
element.classList.add() 替代多次 element.style.xxx = yyy
documentFragment 批量插入节点,避免多次挂载触发重排transfor
m 和 opacity,它们走合成层,不触发重排const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const el = document.createElement('div');
el.textContent = `Item ${i}`;
fragment.appendChild(el);
}
container.appendChild(fragment); // 仅一次真实 DOM 插入
当需要高频判断“是否存在某 key 或某值”时,Object.prototype.hasOwnProperty() 或 array.includes() 是 O(n);而 Map.has() 和 Set.has() 是平均 O(1)。
Map 比普通对象快,且支持任意类型键new Set(arr),比 filter((v, i) => arr.indexOf(v) === i) 快一个数量级很多人一遇到高频回调(如 resize、input)就加 debounce,但容易掩盖真正问题:比如监听了整个窗口 resize 却只为了更新一个元素宽高。
ResizeObserver 观察具体目标元素,而不是全局 resize
debounce 延迟执行,适合搜索建议;throttle 限制频率,适合滚动视差——选错策略会让体验变卡或响应滞后最常被忽略的是:性能瓶颈往往不在 JS 执行本身,而在 DOM 访问模式、内存泄漏(如未清理事件监听器)、或过早优化。先用 Performance 面板录一段真实操作,看火焰图里哪条堆栈占 CPU 最久,再动手改。