7.7 Symbol 包装对象
虽然其它所有原始类型都有字面量形式的值,但是要创建 Symbol 对象,还是得调用Symbol
函数。因此,有时候很容易把 Symbol
函数当成构造函数使用。虽然这会返回 Symbol 的一个实例,但是并没有什么用。所以,如果把 Symbol 函数当成构造函数使用的话,会抛出异常:
> new Symbol()
TypeError: Symbol is not a constructor
有一种创建包装对象的方法:将 Object
当做一个普通函数调用,会将所有的值(包括 Symbol )转换成对象。
> const sym = Symbol();
> typeof sym
'symbol'
> const wrapper = Object(sym);
> typeof wrapper
'object'
> wrapper instanceof Symbol
true
7.7.1 使用 []
和包装对象键访问属性
用来访问属性的方括号操作符 []
会将字符串包装对象和 Symbol 包装对象解包装。我们可以使用如下的对象来检测这个现象。
const sym = Symbol('yes');
const obj = {
[sym]: 'a',
str: 'b',
};
使用交互模式:
> const wrappedSymbol = Object(sym);
> typeof wrappedSymbol
'object'
> obj[wrappedSymbol]
'a'
> const wrappedString = new String('str');
> typeof wrappedString
'object'
> obj[wrappedString]
'b'
7.7.1.1 规范中关于属性访问的说明
获取和设置属性的操作是通过内部的 ToPropertyKey() 操作实现的,其工作过程如下:
- 用 ToPrimitive() 把操作数转换成原始值类型(优先选用
string
类型):- 如果是原始值,就返回自身。
- 对于非 Symbol 对象,如果
toString()
返回原始值,就使用toString()
转换;否则,如果valueOf()
返回原始值,就使用valueOf()
;否则,抛出TypeError
错误。 - Symbol 对象是一个例外:它们会被转换成原始的 Symbol (解包装)。
- 如果转换结果是 Symbol 原始值,直接返回该值。
- 否则,通过 ToString() 强制将结果转换成字符串。