You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
letsym=Symbol();console.log(Boolean(sym))// trueconsole.log(!sym)// falseconsole.log(Number(sym))// Uncaught TypeError: Cannot convert a Symbol value to a numberconsole.log(sym+2)// Uncaught TypeError: Cannot convert a Symbol value to a number
Symbol 作为属性名
Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。
但是,它也不是私有属性,只是属性名有些特殊。有一个Object.getOwnPropertySymbols()方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
Symbol.for(key)
有时,我们希望重新使用同一个 Symbol 值,Symbol.for(key)方法可以做到这一点。它接受一个参数(如果参数不是字符串类型,会执行 ToString() 类型转换操作),然后在 GlobalSymbolRegistry List 中搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该参数为名称的 Symbol 值,并将其注册到 GlobalSymbolRegistry List 中。
ES6 规范中指出,所有通过 Symbol.for(key) 注册的 Symbol 值,都会存放在全局环境的 GlobalSymbolRegistry List 集合中。不管有没有在全局环境运行。即使是在局部作用域中使用 Symbol.for(key),也会将值注册到全局环境中提供搜索。
利用Symbol.for(key)的这个全局登记特性,可以用在不同的 iframe 或 service worker 中取到同一个值。
lets1=Symbol.for('foo');// 第一次执行,即注册名称为 foo 的 Symbol 值lets2=Symbol.for('foo');// 第二次执行,获取到第一次执行时创建的 Symbol 值s1===s2// true
Symbol
ES6 之前对象的属性名只能是字符串,这很容易造成属性名的冲突。
为了解决这一问题,ES6 引入了一种新的原始数据类型 Symbol,用来表示独一无二的值。它是 JavaScript 语言的第七种数据类型。
也就是说,从 ES6 开始,对象的属性名现在可以有两种类型:字符串和 Symbol。
如果对象的属性名是 Symbol 类型的,那么该属性就是独一无二的,可以保证不会与其他任何属性名产生冲突。
生成 Symbol 值
Symbol 值通过
Symbol()
函数生成注意:
Symbol()
函数前不能使用new
命令,否则会报错Uncaught TypeError: Symbol is not a constructor
。这是因为 Symbol 是一个原始类型的值,不是对象。
Symbol Description
Symbol()
函数可以接受一个参数,作为 Symbol 值的描述。如果参数不是字符串类型,会执行 ToString() 类型转换操作。为 Symbol 值添加描述,主要是为了区分不同的 Symbol 值。
如果不添加描述信息,那么它们输出的结果值看起来是相同的(实际并不相等),无法区分。
添加描述信息:
注意:
Symbol()
函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol()
函数的返回值是不相等的。ES2019 提供了一个实例属性
description
,直接返回 Symbol 的描述。类型转换
Symbol 值不能与其他类型的值进行运算,会报错。
也就是说,Symbol 类型值不能进行隐式类型转换。 但是,Symbol 值可以显式转为字符串。
另外,Symbol 值也可以转为布尔值(始终为
true
),但是不能转为数值。Symbol 作为属性名
Symbol 作为属性名,遍历对象的时候,该属性不会出现在
for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。但是,它也不是私有属性,只是属性名有些特殊。有一个
Object.getOwnPropertySymbols()
方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。ES6 中的
Reflect.ownKeys()
方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
Symbol.for(key)
有时,我们希望重新使用同一个 Symbol 值,
Symbol.for(key)
方法可以做到这一点。它接受一个参数(如果参数不是字符串类型,会执行 ToString() 类型转换操作),然后在 GlobalSymbolRegistry List 中搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该参数为名称的 Symbol 值,并将其注册到 GlobalSymbolRegistry List 中。ES6 规范中指出,所有通过
Symbol.for(key)
注册的 Symbol 值,都会存放在全局环境的 GlobalSymbolRegistry List 集合中。不管有没有在全局环境运行。即使是在局部作用域中使用Symbol.for(key)
,也会将值注册到全局环境中提供搜索。利用
Symbol.for(key)
的这个全局登记特性,可以用在不同的 iframe 或 service worker 中取到同一个值。Symbol.keyFor(sym)
Symbol.keyFor(sym)
方法返回一个已注册的 Symbol 值的key。上面代码中,变量 s2 属于未登记的 Symbol 值,所以返回 undefined。
Symbol 应用
消除魔术字符串
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
上面代码中,字符串
Triangle
就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。常用的消除魔术字符串的方法,就是把它写成一个变量。
上面代码中,我们把
Triangle
写成shapeType
对象的triangle
属性,这样就消除了强耦合。如果仔细分析,可以发现
shapeType.triangle
等于哪个值并不重要,只要确保不会跟其他shapeType
属性的值冲突即可。因此,这里就很适合改用 Symbol 值。也就是说,如果一个变量的值没有任何意义,随意取就行的情况下,可以用 Symbol 代替。
内置的 Symbol 值
ES6 提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。
推荐阅读:阮一峰 Symbol
ES2018 新增了 1 个内置的 Symbol 值:
Symbol.asyncIterator
符号指定了一个对象的默认异步迭代器。如果一个对象设置了这个属性,它就是异步可迭代对象,可用于for await...of
循环。参考阅读:
ES2020 新增了 1 个内置的 Symbol 值:
参考阅读:Symbol.matchAll
The text was updated successfully, but these errors were encountered: