JavaScript ES6 Symbol
前言
之前在JavaScript 原型链机制实现in
的时候提到过Symbol.iterator
,虽然明白具体作用,但是感觉到是用来当属性的 key 的,但是为啥这样干…内置的只有Array
有么?
介绍
1 | const foo = Symbol("foo"); |
Symbol
的诞生是 ES6 新添加的数据类型,起初就是设计称为一个属性 key,现在很简单的方式可以得到一个唯一的对象, 比如代码里面的foo === Symbol("foo")
就意味着即便输入description
相同,也不是同一个对象,这就很轻易的定义私有变量或者防止 key 冲突的问题出现。
用法
1 | const foo = Symbol(); |
Symbol
属性不能通过.
的方式来定义。
通过这样的方式定义属性,同时不暴露Symbol
key 值,外部一般手段都没办法使用了,这算是私有变量了。
非常规手段和判断
1 | const foo = Symbol.for("foo"); |
我以前写 Java,也有反射这样的方法来获取和修改,那么 JavaScript 也一定有的,就是通过Object.getOwnPropertySymbols
或Reflect.ownKeys()
来获取所有 key。
如果判断的话就麻烦许多,包括之前谈过的枚举属性,和继承属性,这边的方法其实全记住不太可能…我的做法是记住in
是万能的判断,Object.hasOwnProperty()
是自身所有枚举不枚举和Symbol key
,Object.keys()
只有自身,其他稍微了解一下比较好,具体可以在属性的可枚举性和所有权查阅具体差异。
进阶用法
1 | const foo = Symbol.for("foo"); |
有时候可能需要一些 key 暴露出去,如果用各种传递的方式,其实比较麻烦又容易出错,这个时候就可以用一个 runtime-wide symbol registry(运行时 Symbol 注册)了。
内置 Symbol
一开始提到过的Symbol.iterator
就是其中之一,Symbol
的出现暴露了很多原来 JavaScript 原来无法接触的地方,ES6 就定义了一些内置Symbol
,其实类似 Java 的实现 iterator
接口差不多。
Symbol.iterator
1 | const iterable = {}; |
一开始接触就是这个Symbol
,里面就只是一个iterable
,为了方便的使用,还有generator
的概念,我决定这个今天先不写~
Symbol.hasInstance
在我们用到instanceof
的时候其实就用到了这个Symbol
,具体代码表现是
1 | console.log([] instanceof Array); // true |
每个函数内部其实都有一个Symbol.hasInstance
的方法去判断是否继承自这个函数,所以如果我们改了这个函数…就能输出跟预期不一致的效果。
1 | function Foo() {} |
Symbol.toPrimitive
1 | function Foo(bar) { |
该属性定义在 JavaScript 数据类型的原型上,主要作用就是等数据类型转变会调用此方法,就是1 + '1'
的时候,这个方法参数有三种类型。
Symbol.toStringTag
1 | function Foo() {} |
在我刚转过来写 JavaScript 的时候不太习惯,我在输出obj.toString()
基本只能得到[object Object]
等信息,实际上没有什么帮助,但是Symbol.toStringTag
改变了这个问题。
其他
Symbol.isConcatSpreadable
:一个布尔类型值,在集合对象作为参数传递给Symbol.match
:供 String.prototype.match() 函数使用的一个方法,用于比较字符串。Symbol.replace
:供 String.prototype.replace() 函数使用的一个方法,用于替换子字符串。Symbol.search
:供 String.prototype.search() 函数使用的一个方法,用于定位子字符串。Symbol.species
:用于产生派生对象的构造器。Symbol.split
:供 String.prototype.split() 函数使用的一个方法,用于分割字符串。Symbol.unscopables
:一个对象,其属性指示了哪些属性名不允许被包含在 with 语句中。