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,需要进行一系列重载或者复写底层定义,不太好搞。
相关文档
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。
感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/dpilky 欢迎点赞支持!
欢迎订阅《全栈大道宽又长》https://toutiao.io/subject/77790