Symbol 是唯一不可变的原始值,用于生成永不重复的键;其属性默认不被遍历、序列化,非真正私有;Symbol.for() 可跨作用域复用但有命名污染风险;内置 Symbol 可定制语言行为但需谨慎使用。

Symbol 本质是「唯一不可变的原始值」,不是对象也不是字符串
它最硬核的作用就一个:生成永不重复的键(key)。每次调用 Symbol() 都返回一个全新值,哪怕描述相同:
const a = Symbol('id');
const b = Symbol('id');
console.log(a === b); // false这和字符串 'id' 完全不同——字符串可复用、可比较、可拼接;Symbol 只能比是否同一引用,且不能参与任何运算(Symbol() + 1 直接报 TypeError)。
用作对象属性名时,天然“隐身”于常规遍历和序列化
Symbol 键不会出现在以下操作中:
-
for...in循环里完全看不见 -
Object.keys(obj)和Object.getOwnPropertyNames(obj)都忽略它 -
JSON.stringify(obj)默认丢弃 Symbol 属性
这意味着你用 obj[Symbol('cache')] = {} 加的缓存字段,不会被深拷贝、日志打印、状态序列化意外暴露或覆盖。但注意:它并非真正私有——外部仍可通过 Object.getOwnPropertySymbols(obj) 或 Reflect.ownKeys(obj) 拿到,只是“默认不可见”,适合做模块内标记或中间态字段,别当密码保险柜用。
全局注册表 Symbol.for() 是唯一能跨作用域复用 Symbol 的方式
普通 Symbol() 每次都新造,而 Symbol.for(key) 会查全局注册表,同 key 返回同一 Symbol:
const s1 = Symbol.for('debug');
const s2 = Symbol.for('debug');
console.log(s1 === s2); // true但它有风险:
立即学习“Java免费学习笔记(深入)”;
技术上面应用了三层结构,AJAX框架,URL重写等基础的开发。并用了动软的代码生成器及数据访问类,加进了一些自己用到的小功能,算是整理了一些自己的操作类。系统设计上面说不出用什么模式,大体设计是后台分两级分类,设置好一级之后,再设置二级并选择栏目类型,如内容,列表,上传文件,新窗口等。这样就可以生成无限多个二级分类,也就是网站栏目。对于扩展性来说,如果有新的需求可以直接加一个栏目类型并新加功能操作
- 全局命名空间污染:不同库都用
Symbol.for('config')就撞车了 - 无法回收:注册表里的 Symbol 不会被 GC,长期运行要慎用
- 调试更难:你看到
Symbol(for: "debug"),但不知道是谁注册的
除非写框架级工具(如自定义调试钩子),否则优先用局部 Symbol()。
内置 Symbol(Well-known Symbols)能改写语言行为,但别乱动
像 Symbol.iterator、Symbol.toStringTag 这些是 JS 引擎预留的“钩子”,你实现它们就能定制对象表现:
const obj = {
[Symbol.toStringTag]: 'MyClass',
[Symbol.iterator]: function* () {
yield 1; yield 2;
}
};
console.log(obj.toString()); // "[object MyClass]"
console.log([...obj]); // [1, 2]但要注意:
- 这些方法必须严格按规范实现,比如
[Symbol.iterator]必须返回迭代器对象(含next()方法) - 修改
Symbol.toPrimitive等会影响==、+等隐式转换,极易引发意料外的类型错误 - 浏览器兼容性没问题(ES6+ 全支持),但 Node.js 早期版本(
真正容易被忽略的是:Symbol 键一旦设在对象上,就永远绑定该对象实例——它不像字符串键那样能靠原型链继承,也不进枚举,想动态控制可见性?得自己封装访问器逻辑。









