symbol.unscopables 的设计目的是控制属性在 with 语句中是否可见,避免词法作用域污染和变量遮蔽;它仅影响 with 绑定,不提供运行时保护或私有封装。

Symbol.unscopables 的设计目的不是“保护原始对象内部属性”,而是**控制哪些属性在 with 语句的作用域中不可见**,从而避免污染词法作用域、防止意外覆盖或歧义。它不提供运行时保护,也不阻止直接访问属性,仅影响 with 的绑定行为。
它解决的核心问题:with 语句的变量遮蔽风险
with 会将对象的可枚举属性临时注入当前作用域链。若对象有同名方法(如 includes、indexOf),可能意外覆盖外层变量或内置方法,引发难以调试的行为。例如:
const arr = [1, 2, 3];
let includes = 'custom';
with (arr) {
console.log(includes(4)); // 报错:arr.includes 不是函数(因为被 let includes = 'custom' 遮蔽)
}
ES6 为数组原型添加了 Symbol.unscopables,默认将 includes、flat 等新方法设为 false,使它们在 with 中不可见,从而保持外层 includes 变量有效。
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
如何正确设置 Symbol.unscopables
只需在对象(通常是原型)上定义该 symbol 属性,值为一个对象,键为属性名,值为布尔 false 表示该属性不应进入 with 作用域:
- 必须定义在对象自身或其原型上(
Object.prototype、Array.prototype等已内置) - 仅对
with语句生效,不影响点操作符、方括号或Object.keys() - 不能用于“隐藏”私有字段(如
#field)或防止反射(Reflect.ownKeys仍可见)
自定义示例:
const obj = { foo: 1, bar: 2, internalMethod() {} };
obj[Symbol.unscopables] = { internalMethod: true }; // 或 false,规范用 true 表示“排除”
<p>with (obj) {
console.log(foo); // ✅ 1
console.log(internalMethod); // ❌ undefined(未绑定到作用域)
// internalMethod(); // 报错:not a function
}</p>
重要限制与现实考量
with 本身在严格模式下被禁用,现代代码几乎不用;Symbol.unscopables 主要服务于标准兼容性(如确保旧版 with 代码不因新增 API 崩溃)。因此:
- 不要把它当作安全机制——无法防止
obj.internalMethod被直接调用或遍历 - 不适用于封装私有状态,应使用闭包、
#private字段或WeakMap - 若需真正隔离,优先用模块作用域或
Proxy拦截get/has
替代更可靠的做法
若目标是“防止意外访问内部属性”,推荐以下方式:
- 用
Object.defineProperty设置enumerable: false和configurable: false,隐藏于for...in和JSON.stringify - 使用私有字段
#name(类内强封装,语法级保护) - 导出最小接口,内部实现放在模块顶层作用域,不挂载到公开对象上
- 用
Proxy控制get行为,对敏感属性抛错或返回undefined










