js性能优化关键在于规避隐形杀手:缓存属性访问、读写分离、raf动画、清理闭包引用、精简传参、避免高阶函数链式调用、批量dom操作及合理使用css合成。

JS 运行时性能优化中,真正拖慢体验的往往不是大而明显的错误,而是那些看似无害、日常编码中随手写出的“隐形性能杀手”。它们不报错、不影响功能,却在高频执行、大数据量或长期运行时持续消耗 CPU、阻塞主线程、累积内存,最终导致卡顿、掉帧甚至页面无响应。
循环里反复访问深层属性或 DOM 几何值
每次读取 arr[i].data.items.length 或 element.offsetTop,V8 都要逐层查对象属性,浏览器也可能被迫同步计算布局(强制重排)。在 1 万次循环中重复这个操作,开销会指数级放大。
- 把中间结果缓存为局部变量:
const len = arr.length、const items = obj.data.items、const rect = el.getBoundingClientRect() - 读写分离:先集中读完所有需要的几何值(
rect.top、rect.height),再统一写样式;避免“读→写→读→写”交错 - 动画场景下,用
requestAnimationFrame包裹更新逻辑,确保批量执行
闭包意外持有大对象或长生命周期引用
闭包本身很快,但一旦函数被事件监听器、定时器或全局 Map 持有,它捕获的整个外层作用域就无法被垃圾回收——哪怕你只用了其中一两个字段。
- 组件销毁或离开页面前,主动清理:
clearTimeout、removeEventListener、observer.disconnect() - 传参精简:事件回调中不要传整个对象,改传关键 ID 或必要字段,例如
onClick={() => handler(item.id)} - 用
WeakMap存储关联数据,键对象被回收时,对应条目自动失效
滥用 Array 高阶函数做条件筛选或提前终止
filter().find()、map().some() 这类链式调用,会在每一步生成新数组,全量遍历且无法中途退出。对 10 万条数据找第一个偶数,filter 先建一个几万项的新数组,纯属浪费。
- 明确“找一个就停”时,直接用
for或for...of循环,遇到目标立即break - 去重优先考虑
new Set(arr)而非[...new Set(arr)],省一次展开运算 - 拼接数组用
push批量添加,比concat或扩展运算符更省内存
未节制的 DOM 操作与同步布局触发
连续修改 style.color、style.fontSize,或一边读 offsetHeight 一边改 style.width,都会让浏览器反复重排,形成“布局抖动”(layout thrashing)。
- 批量写入:用
className切换预设样式,或一次性设置cssText - 动画优先用
transform和opacity,它们走合成层,不触发布局计算 - 给频繁动画的元素加
will-change: transform,但别滥用,防止合成层过多吃内存











