一、问题导入
先看一段有关Symbol的代码:
// 创建一个Symbol类型变量
const sym = Symbol('test')
// 调用Symbol的toString方法,返回正常
console.log(sym.toString())
// Symbol类型变量如果在数组中,并且对数组进行toString操作则会报错
console.log([sym].toString())
看一下具体的运行结果:
按照Array.prototype.toString的逻辑,应该是会对数组的每个元素进行字符串化,那么上述二者应该是一样的结果。但实际可以看到:
Symbol('test').toString()
和 [Symbol('test')].toString()
形式上相似,但结果却完全不同。
二、原因调查
这个我们翻阅一下Ecmascript的规范来看看:
首先,从上图看,在数组中的元素在调用toString时,会调用到join方法。接着再来看看有关Array.prototype.join的说明:
从上可知,join里面会用到一个抽象操作ToString:
在ToString的说明里就明确规定:如果参数类型是Symbol,则直接抛出一个TypeError异常。
我们再来看看Symbol('test').toString()
经历了什么:
首先,思考Symbol(‘test’).toString是哪来的?它是Object.prototype.toString吗?
答案是否定的。不信可以用Object.prototype.toString === Symbol('test').toString
去判断。
Symbol.prototype.toString
其实在规范中也有规定:
它的结果其实就是Symbol变量在创建时的描述字符串按照特定的格式进行返回。具体怎么返回可以看一下规范的详细定义:
上述描述比较浅显,就不多解释。