JavaScript变量访问性能开销主要源于作用域链逐层查找,缓存全局对象、方法引用、避免隐式全局和with语句、循环中缓存.length可显著提升性能。

JavaScript 中变量访问的性能开销,主要来自作用域链的逐层查找。每次读取一个未声明在当前作用域的变量(比如 document、window 或深层嵌套对象的属性),引擎都要从当前执行上下文开始,一层层向上遍历作用域链,直到找到目标或抵达全局作用域。这个过程是线性时间复杂度 O(n),嵌套越深、链越长,开销越大。
缓存全局对象到局部变量
全局对象(如 document、Math、console)在作用域链顶端,每次访问都需完整遍历。只需在函数开头用局部变量保存一次,后续所有调用都走局部作用域——而局部变量位于作用域链最前端,访问速度最快。
- 低效写法:反复访问
document.getElementById或document.body - 优化写法:
const doc = document; const body = doc.body;,之后统一用doc和body - 适用场景:DOM 操作密集的函数、循环体内部、高频回调中
缓存对象属性和方法引用
对象属性访问(如 obj.method)比读取普通变量慢,因为要先定位对象,再在其属性中查找(可能涉及原型链)。若某个方法被多次调用,可提前提取为局部变量。
- 例如:
const push = arr.push;,后续用push(item)替代arr.push(item) - 注意:仅适用于不依赖
this的纯函数方法;若方法内部使用this,需用.bind()或箭头函数绑定上下文 - 常见受益对象:
Array.prototype方法、JSON.parse、Date.now等
避免隐式全局与 with 语句
未声明直接赋值(如 foo = 'bar')会创建隐式全局变量,不仅污染全局环境,还让后续对 foo 的读取必须走完整作用域链。同样,with 语句会临时插入一个作用域,强制引擎多查一层,显著拖慢变量访问。
- 始终用
let/const显式声明变量 - 禁用
with,改用显式对象访问(obj.prop而非with(obj) { prop }) - ESLint 规则
no-with和no-implicit-globals可自动拦截这类问题
循环中缓存 .length 和集合引用
HTMLCollection 或 NodeList 是“实时集合”,每次访问 .length 都会触发 DOM 重新查询;在 for 循环中反复读取,开销叠加明显。
- 错误写法:
for (let i = 0; i —— 每次迭代都查 length - 正确写法:
const len = list.length; for (let i = 0; i - 更进一步:把
list本身也缓存为局部变量,尤其当它来自document.querySelectorAll等开销较大 API 时











