ECMAScript 标准的十万个为什么 - Symbol 的隐式转换
今天苏老师发了一篇:Symbol Polyfill 填坑之旅,文章中提到 Symbol 隐式转换的问题,作为一个只在文章中看过 Symbol 的萌豚,我也想知道究竟为什么 Symbol 可以有
toString()
方法,却不能进行'' + Symbol('word')
的操作。
标准
在 MDN - Symbol 中有一些规则,它告诉我们当 Symbol 尝试隐式类型转换时会报错,但是为什么会这样,底层是是怎么实现的,我们还是不太清楚。
Symbol 类型转换
当使用 symbol 值进行类型转换时需要注意一些事情:
尝试将一个 symbol 值转换为一个 number 值时,会抛出一个 TypeError 错误 (e.g. +sym or sym | 0).
使用宽松相等时, Object(sym) == sym returns true. 这会阻止你从一个 symbol 值隐式地创建一个新的 string 类型的属性名。例如,Symbol("foo") + "bar" 将抛出一个 TypeError (can't convert symbol to string).
"safer" String(sym) conversion works like a call to Symbol.prototype.toString() with symbols,但是注意 new String(sym) 将抛出异常。
标准实现
我们从底层标准看起,首先看 +
时发生了什么:
Let lref be the result of evaluating AdditiveExpression. Let lval be ? GetValue(lref). Let rref be the result of evaluating MultiplicativeExpression. Let rval be ? GetValue(rref). Let lprim be ? ToPrimitive(lval). Let rprim be ? ToPrimitive(rval). If Type(lprim) is String or Type(rprim) is String, then Let lstr be ? ToString(lprim). Let rstr be ? ToString(rprim). Return the String that is the result of concatenating lstr and rstr. Let lnum be ? ToNumber(lprim). Let rnum be ? ToNumber(rprim).
会在左值和右值赋值之后依次执行 GetValue
和 ToPrimitive
,对于 String 和 Symbol 而言,会返回原来的值。接下来,假设操作为 '' + Symbol('word')
,左值为 String ,执行 ToString
操作,此处的 ToString
并不是我们所说的原型链上的 toString
方法,我们需要接着往下看:
换句话说,在 ToString 方法内部判断了值类型,根据类型进行后续不同的操作,而不是简单的调用 toString()
方法,对于 Symbol 类型,它的处理就是抛出异常。
如果我们需要 polyfill,需要进行一系列重载或者复写底层定义,不太好搞。
评论 (1)
感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/dpilky 欢迎点赞支持! 欢迎订阅《全栈大道宽又长》https://toutiao.io/subject/77790