JavaScript 里最神秘的类型:Symbol,为什么老程序员都离不开它?

33 阅读3分钟



大家好,我是 31 岁、爱折腾代码、也爱把技术讲成故事的小米。

那天我在公司翻一段老代码,突然看到一行东西:

我当场愣了三秒。这玩意儿,不像字符串,不像数字,也不像对象,却能左右 for...of、影响数组拼接、甚至决定 instanceof 的结果。

就像一个江湖高手平时不露脸,一出手,全是内功。

今天我们就来讲讲 JavaScript 里这个最“神秘”的基础类型:Symbol

符号的基本用法:一人一令,绝不撞号

先讲故事。

想象你在一个大型门派里,每个弟子都有一块令牌。名字可以重名,外号可以重复,但令牌编号,绝不可能一样。Symbol 就是这样。

1. Symbol 是什么?

Symbol 是 ES6 新增的一种原始数据类型,它的特点只有一句话:

每一个 Symbol,都是独一无二的。

哪怕你写得一模一样,它们也不是同一个。你还可以给 Symbol 一个“描述”,方便调试:

注意一句非常重要的话:描述只是标签,不是标识。

使用全局符号注册表:江湖通用暗号

有些时候,你不是想“一人一令”,而是想:全江湖,只认这一块令牌。

这时候,就要用 全局符号注册表

1. Symbol.for

Symbol.for(key) 会做两件事:

  1. 去全局注册表里找
  2. 有就返回,没有就创建并登记

2. Symbol.keyFor

反查用的:

注意:

只有通过 Symbol.for 创建的,才在全局表里。

使用符号作为属性:对象里的“暗格抽屉”

现在进入 Symbol 最常见、也最实用的场景。

1. 为什么要用 Symbol 当属性?

因为它有三个特性:

  1. 不会被意外覆盖
  2. 不会出现在 for...in
  3. 非常适合做“内部属性”

就像一个柜子里的暗格

2. 枚举行为对比

常用内置符号:语言级别的“机关按钮”

如果说普通 Symbol 是你自己造的令牌,那 内置 Symbol,就是 JavaScript 官方留下的“后门接口”。

它们都挂在 Symbol.xxx 上。

Symbol.asyncIterator:异步流水线

这个符号决定一件事:对象能不能被 for await...of 遍历

这是 Node.js、流式处理、异步任务队列的基础。

Symbol.hasInstance:重写 instanceof 规则

instanceof 就像门派认人:“你是不是我门下的?”

Symbol.hasInstance 允许你自定义这套逻辑

是不是很“不讲武德”?但在框架设计里,非常有用。

Symbol.isConcatSpreadable:数组拼接的开关

默认情况下:

但你可以让数组拒绝展开

Symbol.iterator:可迭代对象的通行证

这可能是最重要的 Symbol。只要对象实现了它,就能:

  • for...of
  • 解构
  • 展开运算符

Symbol.match:正则的“匹配资格证”

当你写:

JS 实际会去找:

Symbol.replace:自定义 replace 行为

Symbol.search:定义搜索逻辑

Symbol.species:构造器血统问题

它决定:派生对象,用谁来 new?

Symbol.split:拆分规则定制

Symbol.toPrimitive:对象如何变成原始值

这是 JavaScript 类型转换的终极开关

Symbol.toStringTag:改写 Object.prototype.toString

Symbol.unscopables:with 语句里的“免打扰名单”

这个 Symbol 决定:哪些属性,不应该被 with 拿出来

Symbol 是什么样的人?

如果用一句话形容 Symbol:

它不争曝光,却掌控规则。

它解决了属性冲突

它为语言提供了“协议接口”

它是 JS 内部机制的钥匙

当你开始理解 Symbol,你会发现:

JavaScript 这门语言,真的在认真设计。

END

如果你觉得这篇文章对你理解 Symbol 有帮助,欢迎点赞、收藏、转发。

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!