with语句将对象临时插入作用域链顶端,导致变量查找动态化,引发性能下降和可维护性问题;严格模式下被语法禁止,应使用解构、局部变量等现代语法替代。

with 语句会把指定对象**临时插入当前作用域链的最前端**,让后续未加限定的变量名优先从该对象上查找;但它不改变函数定义时确定的词法作用域,只在执行时动态调整查找路径。这种“动态增强”看似方便,却带来明确的性能与可维护性隐患。
with 如何修改作用域链
JavaScript 引擎在查找变量时,按作用域链从内到外逐层搜索。with 语句会在执行其代码块期间,将传入的对象(如 obj)作为新的顶层变量对象(VO)推入作用域链头部:
- 原本作用域链可能是:
[当前VO] → [父函数VO] → [全局VO] - 执行
with(obj)后变为:[obj] → [当前VO] → [父函数VO] → [全局VO] - 当代码中出现未声明的标识符(比如
name),引擎先查obj.name,再查其他层级 - 若
obj没有该属性,且未用var/let/const声明,就会报ReferenceError
它为什么导致性能下降
引擎无法在编译阶段静态分析变量归属,因为 with 块内的变量引用可能指向任意对象属性,也可能意外落到外层作用域 —— 这种不确定性迫使优化器放弃内联、缓存等关键优化策略:
- 每次变量访问都需运行时遍历整个作用域链,无法提前绑定到具体内存位置
- V8 等现代引擎会将含 with 的函数标记为“不可优化”,降级到解释执行模式
- 实测循环中使用 with 访问对象属性,比直接写
obj.prop慢 2–5 倍(尤其在大量迭代场景) - 即使块内只读不写,只要存在 with,整个函数体都会受牵连
严格模式下直接被禁用
ECMAScript 5 起,"use strict" 中使用 with 会立即抛出 SyntaxError,不是运行时报错,而是语法解析失败:
- 这是语言层面的否定,说明设计者认定其行为不可靠
- 所有主流打包工具(如 Webpack、Vite)默认启用严格模式,with 代码根本无法通过构建
- 即便非严格环境,Chrome/Firefox 已对 with 发出控制台警告,提示“deprecated”
替代方案更清晰安全
想简化对象属性访问,完全可用现代语法替代,语义明确且无副作用:
- 解构赋值:
const { href, protocol } = location; - 对象展开或局部变量:
const { search, hostname, href } = location; - 箭头函数封装:
const useLocation = f => f(location); useLocation(({href}) => console.log(href)); - 需要动态属性名?用方括号访问:
obj[key]或Reflect.get(obj, key)



















