避免在循环中重复计算数组长度,应缓存 arr.length;去重优先用 Set;防抖节流需按场景选用,避免滥用;优先优化 DOM 访问和内存泄漏,再考虑 JS 执行性能。

避免在循环中重复计算数组长度
常见错误是把 arr.length 直接写在 for 循环条件里,尤其当数组很大或 length 被代理/访问器劫持时,每次迭代都触发 getter,开销明显。
- 用变量缓存:
const len = arr.length; for (let i = 0; i - 对普通数组,现代引擎(V8、SpiderMonkey)多数能自动优化,但不保证;对
HTMLCollection或带 getter 的类数组对象,必须手动缓存 - 更安全的替代是使用
for...of,它不依赖length,且语义清晰
减少 DOM 操作频次与重排重绘
每次读写 offsetTop、clientWidth 或修改 style 属性,都可能触发强制同步布局(forced synchronous layout),性能杀手。
- 批量读取:先集中读所有需要的尺寸,再集中写样式
- 批量写入:用
element.classList.add()替代多次element.style.xxx = yyy - 用
documentFragment批量插入节点,避免多次挂载触发重排 - 动画优先用
transform和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 插入
善用 Map/Set 替代对象/数组做查找
当需要高频判断“是否存在某 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)快一个数量级 - 注意:如果只是少量静态配置(如 5 个状态映射),对象字面量反而更轻量,别过度设计
函数防抖与节流不是万能解药
很多人一遇到高频回调(如 resize、input)就加 debounce,但容易掩盖真正问题:比如监听了整个窗口 resize 却只为了更新一个元素宽高。
立即学习“Java免费学习笔记(深入)”;
- 优先缩小监听范围:用
ResizeObserver观察具体目标元素,而不是全局resize -
debounce延迟执行,适合搜索建议;throttle限制频率,适合滚动视差——选错策略会让体验变卡或响应滞后 - 简单逻辑(如开关 class)可直接内联处理,加一层防抖函数反而增加闭包和定时器开销
最常被忽略的是:性能瓶颈往往不在 JS 执行本身,而在 DOM 访问模式、内存泄漏(如未清理事件监听器)、或过早优化。先用 Performance 面板录一段真实操作,看火焰图里哪条堆栈占 CPU 最久,再动手改。











