symbol.unscopables 是内置 symbol,仅控制 with 语句中对象自有属性是否被注入作用域链顶部,不保护原型属性、不阻止原型访问,仅影响词法绑定;现代代码应避免使用 with,改用解构、proxy 或私有字段等更安全方案。

Symbol.unscopables 是一个内置 symbol,用于控制对象在 with 语句作用域中哪些属性**不被暴露**。它不能“保护原型属性”本身,也不能阻止原型链访问,它的作用非常具体:仅影响 with 块内标识符的词法绑定行为——即决定哪些自有属性名**不会被自动添加到 with 创建的作用域链顶部**。
它解决什么问题?
with 会把对象的**可枚举自有属性**(不包括原型链上的)临时注入当前作用域,导致变量名可能意外覆盖或遮蔽外部同名变量。例如:
let x = 'global';
const obj = { x: 'local', y: 42 };
with (obj) {
console.log(x); // 'local' —— 覆盖了外层 x
console.log(y); // 42
}
如果某天 Array.prototype 添加了一个新方法(如 flatMap),而你又用 with (arr),就可能意外捕获该方法名,干扰代码逻辑。ES6 为避免这类兼容性风险,给 Array.prototype 设置了 Symbol.unscopables,将 includes、flat 等新方法排除在 with 作用域之外。
如何正确使用 Symbol.unscopables?
只需在对象上定义一个名为 Symbol.unscopables 的属性,其值为一个对象,键是**要屏蔽的自有属性名**,值为 true:
- 只对对象自身的属性生效,不影响原型链上的属性是否可访问(
obj.prop依然能正常读取原型属性) - 仅在
with内部标识符解析时起作用;不影响点操作符、方括号访问或 Object.keys() 等任何其他方式 - 该 symbol 属性必须是**可枚举的 false**(默认就是),否则
with不识别
const safeObj = {
secret: 'hidden',
public: 'visible'
};
<p>// 告诉 with:不要把 'secret' 加入作用域
safeObj[Symbol.unscopables] = {
secret: true
};</p><p>let secret = 'outer';</p><p>with (safeObj) {
console.log(public); // 'visible' —— 正常暴露
console.log(secret); // 'outer' —— 未被覆盖!因为被 unscopables 屏蔽
}</p>
注意:它不是安全机制,也不防原型污染
Symbol.unscopables 和“保护原型属性”没有直接关系:
- 它不阻止你通过
obj.__proto__.method或Object.getPrototypeOf(obj).method访问原型方法 - 它不防止原型被修改(如
Array.prototype.custom = ...) - 它不提供任何运行时防护,仅影响
with的静态绑定规则 -
with本身已被严格模式禁用,现代代码应避免使用
替代方案更实用
既然 with 已过时且危险,真正需要“保护属性”或“控制暴露”的场景,推荐:
- 用
Object.freeze()或Object.defineProperty()控制属性的可写/可枚举性 - 用
class+#private字段实现真正私有数据 - 用 Proxy 拦截
get/has,动态控制属性可见性 - 避免依赖
with,改用解构赋值:const { public } = safeObj;










