对于 Symbol
的理解,一直比较陌生,只知道他是 ES6
的语法规范,具体概念,可参考阮一峰老师的 Symbol
文章。这里我就自己的理解写,不讲概念,写一个容易理解的demo,介绍 Symbol
的作用。
传统obj key值的痛点
一个亿万富豪,有几个儿子和女儿,还有一私生子,如果此时,我们直接这样定义这个亿万富豪:
1 | let billionaire = { |
在控制台我们会发现,私生子bastard 会直接覆盖掉前面的son,这显然是不合适的
于是 Symbol
作为ES里原始的数据类型的作用就出现了
利用 Symbol
添加私生子, 解决痛点
正确的做法应该如下,先定义了儿子和女儿们:
1 | let billionaire = { |
把私生子 son: 'bastard'
单独抽出来,用 Symbol
定义,以下有3种定义方法:
1 | const son = Symbol('son') |
至此,Symbol
的作用很明确了,
由于 JS 的 obj key值为字符串,为了避免 JS 的 obj 中属性名字的冲突而产生
私生子身份神秘,普通new,. 等方法对其无效,只有亿万富翁自己知道
由于 Symbol
是原始类型,没有构造函数,不能使用 new
关键字
也不能用 . 运算将其点出来:
私生子的身份确认如何得到保障?
作为亿万富豪的私生子,只有亿万富豪自己一个人知道其身份,所以,我们用普通方法是找不到这个私生子的:
而私生子有独特的方法能得到确认,Symbol
为我们提供了几种方法
Object.getOwnPropertySymbols()
1 | const querySon = Object.getOwnPropertySymbols(billionaire) |
多个私生子
亿万富豪也可能有不止一个私生子,比如和 ‘知己小秘’ 生了一个私生子,和 ‘灵魂伴侣’ 又生了一个私生子,此时我们可以用 Symbol.for()
定义:
1 | const bastard1 = Symbol.for('知己小秘') |
1 | { |
Symbol
key值同名时,其 value 也能被覆盖掉
如果 ‘灵魂伴侣’ 又生多了一个私生子 ‘灵魂伴侣儿子2’ ,会出现什么情况?
1 | const bastard3 = Symbol.for('灵魂伴侣') |
直接打印出来,会发现 value 值 ‘灵魂伴侣儿子2’ 覆盖掉了 ‘灵魂伴侣儿子1’
1 | { |
bastard2
和 bastard3
都是Symbol值,它们都是由同样参数的 Symbol.for
方法生成的key,所以实际上是仍是同一个值:
1 | console.log(bastard2 === bastard3) |
查询所有儿女,包括私生子的Key值:Reflect.ownKeys()
会以一个数组返回所有 Key 值,包括 Symbol Key
1 | console.log(Reflect.ownKeys(billionaire)) |
Symbol.for()
和 Symbol()
生成的Key值有何不同
Symbol.for()
会被登记在全局环境中供搜索,而 Symbol()
就不会,我们改动私生子为 Symbol()
生成,如:
1 | const bastard1 = Symbol.for('知己小秘') |
换句话说,Symbol.for()
每次生成前,会检查全局环境中是否存在该Key;Symbol()
则不会,每次调用会每次都生成
1 | console.log(Symbol.for('a') === Symbol.for('a')) |