7.5 Symbol 转换成其他原始类型
下面的表格展示了 Symbol 在显示地或者隐式地转换成其他原始类型的时候会发生什么:
转换成 | 显示转换 | 隐式转换 |
---|---|---|
boolean | Boolean(sym) → OK | !sym → OK |
number | Number(sym) → TypeError | sym*2 → TypeError |
string | String(sym) → OK | ''+sym → TypeError |
sym.toString() → OK | `${sym}` → TypeError |
7.5.1 当心:隐式转换成字符串
禁止隐式转换成字符串会很容易导致下面的错误:
const sym = Symbol();
console.log('A symbol: '+sym); // TypeError
console.log(`A symbol: ${sym}`); // TypeError
要修复这些问题,需要显示转换成字符串:
console.log('A symbol: '+String(sym)); // OK
console.log(`A symbol: ${String(sym)}`); // OK
7.5.2 理解隐式转换规则
通常会禁止 Symbol 的隐式转换。本节讲解了为什么会这样。
7.5.2.1 允许真值检查
隐式转换成布尔值是始终可以的,主要用于在 if 语句中检查真值情况以及其他一些场景:
if (value) { ··· }
param = param || 0;
7.5.2.2 意外地将 Symbol 用作属性键
Symbol 是一种特殊的属性键,这就是为什么需要避免意外地将其转换成字符串(字符串是另一种类型的属性键)。在使用一些操作符来计算属性名的时候,这种意外错误就可能发生:
myObject['__' + value]
这就是为啥 value
是 Symbol 的时候会抛出 TypeError
错误。
7.5.2.3 意外地将 Symbol 用作数组索引
你肯定也不期望意外地将 Symbol 用作数组索引。下面的代码展示了当 value
是 Symbol 的时候,这种错误就会发生:
myArray[1 + value]
这就是为什么在这种场景中,该操作会抛出错误。
7.5.3 规范中的显示转换和隐式转换
7.5.3.1 转换成布尔类型
可以使用 Boolean() 显示地将 Symbol 转换成布尔类型。对于 Symbol 类型,会始终返回 true
:
> const sym = Symbol('hello');
> Boolean(sym)
true
Boolean()
通过内部的 ToBoolean() 操作计算出最终结果。对于 Symbol 和其他真值,该操作返回 true
。
隐式转换同样使用 ToBoolean()
:
> !sym
false
7.5.3.2 转换成数值类型
使用 Number() 将 Symbol 显示地转换成数值类型:
> const sym = Symbol('hello');
> Number(sym)
TypeError: can't convert symbol to number
Number()
通过内部的 ToNumber() 操作计算出最终结果,对于 Symbol ,该操作会抛出 TypeError
。
隐式转换也会使用 [ToNumber()] :
> +sym
TypeError: can't convert symbol to number
7.5.3.3 转换成字符串
使用 String() 将 Symbol 转换成字符串:
> const sym = Symbol('hello');
> String(sym)
'Symbol(hello)'
如果 String()
的参数是 Symbol ,那么该方法会自己将其转换成字符串,然后返回用创建 Symbol 的时候传入的描述字符串(使用 Symbol()
包裹起来)。如果没有提供描述字符串,就会使用空字符串:
> String(Symbol())
'Symbol()'
toString()
方法返回和 String()
相同的结果,但是都不会调用对方,它们都会调用内部的操作 SymbolDescriptiveString() 。
> Symbol('hello').toString()
'Symbol(hello)'
隐式转换是通过内部的 ToString() 操作来处理的,对于 Symbol ,会抛出 TypeError
。Number.parseInt()
方法会隐式地将参数转换成字符串:
> Number.parseInt(Symbol())
TypeError: can't convert symbol to string
7.5.3.4 不允许:使用双目加号操作符(+)转换
加号操作符的处理过程是这样的:
- 将两边的操作数转换成原始类型。
- 如果某一个操作数是字符串,那么另一个操作数会被隐式转换成字符串(使用
ToString()
),然后将它们串联起来,返回结果。 - 否则,将两个操作数都转换成数值类型,然后相加,返回结果。
隐式转换成字符串和数值都会抛出异常,这意味着不能(直接)将加号运算符用于 Symbol 。
> '' + Symbol()
TypeError: can't convert symbol to string
> 1 + Symbol()
TypeError: can't convert symbol to number