with语句将对象临时添加到作用域链头部,使属性可直接访问,但因破坏词法作用域、阻碍编译优化、调试困难,ECMAScript 5严格模式下已被完全禁用,属已淘汰语法。

with 语句到底做了什么
with 是 JavaScript 中一个被废弃的语法结构,它允许你临时将某个对象添加到作用域链头部,使得该对象的属性可以像局部变量一样直接访问。
比如:
const obj = { x: 1, y: 2 };
with (obj) {
console.log(x + y); // 不报错,x 和 y 被解析为 obj.x / obj.y
}
这看起来方便,但实际执行时,JS 引擎必须在每次读取 x 或 y 时,先检查它们是否是 obj 的自有属性,再沿作用域链向上查找——这个过程无法在编译期确定,导致所有相关变量访问都失去优化可能。
为什么严格模式下直接禁用
ECMAScript 5 开始,with 在严格模式("use strict")中被完全禁止,尝试使用会抛出 SyntaxError: Strict mode code may not include a with statement。
原因很实际:
- 它让代码的词法作用域变得动态且不可静态分析
- 引擎无法进行变量提升、内联、常量折叠等基本优化
- 调试器难以准确定位变量来源,堆栈信息模糊
- 与
eval类似,属于“破坏作用域透明性”的设计
常见误用场景和替代写法
过去有人用 with 简化 DOM 操作或配置对象嵌套访问,例如:
立即学习“Java免费学习笔记(深入)”;
with (document.getElementById('form').elements) {
username.value = '';
password.value = '';
}
这种写法现在应改用解构或显式引用:
const form = document.getElementById('form');
const { username, password } = form.elements;
username.value = '';
password.value = '';
或者更安全地逐个获取:
const form = document.getElementById('form');
form.elements.username?.value = '';
form.elements.password?.value = '';
要点:
- 永远不要依赖
with来“省略前缀” - 对象属性访问明确优于隐式作用域注入
- 现代工具链(如 ESLint)默认会报
no-with错误
它还在哪些地方悄悄出现
虽然你不会主动写 with,但某些旧库或压缩后的代码(尤其是早期 Closure Compiler 输出)可能残留。另外,非严格模式下的浏览器控制台里仍可执行,但这不代表它安全。
真正容易被忽略的是:即使整个脚本没写 with,只要某处用了 eval 并传入含 with 的字符串,也会触发禁用逻辑或运行时错误——而这类间接调用极难排查。
所以不是“不推荐”,而是“已淘汰”。现在看到它,就当看见一段需要重构的遗留代码。










