Symbol属性默认不可枚举,不参与for...in、Object.keys()等遍历,但可通过Object.getOwnPropertySymbols()或Reflect.ownKeys()获取;其enumerable始终为false,而writable和configurable可修改;与#field不同,Symbol非语法级私有,仅隐藏于枚举。

Symbol 类型的属性默认不会出现在 for...in、for...of、Object.keys()、Object.getOwnPropertyNames() 等遍历或枚举操作中,但它确实是对象自身的、可配置的、可写的属性(除非显式设置为不可写/不可配置),只是“不可枚举”(enumerable: false)——这是它作为“私有”或“内部”键的核心机制之一。
Symbol 属性不参与常规枚举
使用 Symbol() 创建的键被添加到对象上后,其描述符中的 enumerable 为 false。这意味着:
-
Object.keys(obj)和Object.getOwnPropertyNames(obj)都不会返回 Symbol 键(后者只返回字符串键) -
for...in循环跳过所有 Symbol 属性(只遍历可枚举的字符串键) -
JSON.stringify(obj)忽略 Symbol 键(既不序列化键也不序列化值)
Symbol 属性仍可通过 Reflect.ownKeys 或 getOwnPropertySymbols 获取
虽然不可枚举,但 Symbol 键是对象的自有属性,可通过专门方法访问:
-
Object.getOwnPropertySymbols(obj):返回对象上所有自有 Symbol 键组成的数组 -
Reflect.ownKeys(obj):返回所有自有键(含字符串 + Symbol),顺序为:先字符串键(按创建顺序),再 Symbol 键(按创建顺序)
例如:
立即学习“Java免费学习笔记(深入)”;
const sym1 = Symbol('a');const sym2 = Symbol('b');
const obj = { x: 1, [sym1]: 's1', y: 2, [sym2]: 's2' };
console.log(Reflect.ownKeys(obj)); // ['x', 'y', Symbol(a), Symbol(b)]
Symbol 属性的 descriptor 可被显式修改(但 enumerable 始终为 false)
通过 Object.defineProperty 设置 Symbol 属性时,你无法将其 enumerable 改为 true —— JavaScript 强制保持 enumerable: false:
- 即使写
enumerable: true,实际 descriptor 中仍是false - 但
writable、configurable可正常设置(默认均为true) - 验证方式:
Object.getOwnPropertyDescriptor(obj, sym)
与私有字段 #field 的本质区别
Symbol 不是语法级私有,只是“隐藏于枚举”,而 #field 是真正不可外部访问的私有字段:
- Symbol 键可被任意代码通过
getOwnPropertySymbols发现和读写 -
#field在类外完全不可见,连Reflect.ownKeys都不出现 - Symbol 更适合“弱私有”场景(如库内部约定键名、避免冲突),而非强封装


















