应避免在循环中重复计算数组长度、滥用事件监听器、用try...catch包裹高频代码:需缓存length、用事件委托替代单元素绑定、移除非必要try...catch以提升V8性能。

避免在循环中重复计算数组长度
写 for (let i = 0; i 是常见写法,但每次迭代都访问 arr.length 属性,在老旧引擎或频繁调用场景下有微小开销。现代 JS 引擎大多已优化该模式,但若数组可能被修改、或运行在嵌入式环境(如某些 IoT 设备的 JS 引擎),仍建议缓存长度值。
- 推荐写法:
for (let i = 0, len = arr.length; i - 更安全的替代:用
for...of遍历值,或arr.forEach()—— 它们不暴露索引/长度,语义清晰且引擎优化充分 - 注意:如果循环体中会修改
arr(如push/splice),缓存长度反而会导致逻辑错误,此时必须实时读取arr.length
减少闭包中对外部作用域的引用
闭包本身不是性能杀手,但若内部函数无意中捕获了大型对象(比如整个 DOM 节点、大数组或未清理的定时器引用),会导致这些对象无法被垃圾回收,长期驻留内存。
- 典型陷阱:
function makeHandler(node) { return function() { console.log(node.innerHTML); }; }—— 即使node后续从 DOM 移除,只要 handler 存在,node就不会被释放 - 缓解方式:只捕获真正需要的字段,例如
const html = node.innerHTML; return () => console.log(html); - 监听器场景下,优先使用事件委托 +
event.target,而非为每个元素绑定独立闭包
慎用 try...catch 包裹高频代码
在 V8 等主流引擎中,try...catch 块会阻止部分 JIT 编译优化(如内联、逃逸分析),尤其当它包裹在循环或热路径函数中时,可能显著拖慢执行速度。
- 不要这样写:
for (let i = 0; i - 更优做法:提前校验输入类型或结构,把异常处理移到外围;或改用返回错误对象的纯函数(如
parseJSON(str)返回{ ok: true, value: ... }或{ ok: false, error: ... }) - 仅在真正「可能失败且需立即响应」的场景用
try...catch,比如 JSON 解析、localStorage.setItem、跨 iframe 访问
DOM 操作尽量批量 & 脱离文档流
每次读写 DOM 都可能触发重排(reflow)或重绘(repaint),而连续读写混合会强制浏览器同步计算样式,开销陡增。
立即学习“Java免费学习笔记(深入)”;
- 避免「读-写-读-写」模式:
el.offsetWidth; el.className = 'a'; el.offsetHeight; el.className = 'b'; - 批量写入:用
documentFragment组装节点再一次性挂载;或用el.innerHTML = str替代多次appendChild - 读写分离:先集中读取所有需要的尺寸/样式(如用
getBoundingClientRect()批量获取),再统一写入变更 - CSS 动画优先用
transform和opacity,它们走合成层,不触发布局计算











