符号


在 ECMAScript 6 中,基本数据类型除了numberstring与布尔值boolean,还多了一个symbol

在过去,若需要表示一个独立无二的符号(名称),会使用字符串来临时权充,然而,字符串本身可用来描述人、事、时、地、物等,虽然也可用来描述符号,不过,同样'x',在 A 场合可能代表某个意义,然而 B 场合可能就代表另一意义。

若确实需要的是一个独一无二的符号,在 ECMAScript 6 中,可以使用symbol,它是专门为符号而设计,可以使用Symbol函数来创建symbol类型的值。例如:

> let x = Symbol()
undefined
> let y = Symbol('The description of this symbol')
undefined
>

使用Symbol时指定的字符串只是个描述,调用Symbol时可以不指定描述,若指定了,该描述只是对符号的说明,不代表符号!

在 A 场合定义了Symbol('x'),那这个符号的定义就是独一无二的,如果 B 场合定义了Symbol('x'),它是另一个独一无二的定义。具体来说,Symbol('x') === Symbol('x')会是false

> Symbol('x') === Symbol('x')
false
>

每个新创建的符号都会是独一无二,只不过它们都刚好有个描述叫做'x',创建符号时指定的字符串,应该用来描述符号的用途,对符号使用toString,返回的字符串会是把描述放在 Symbol() 之中:

> Symbol('for each method of xxx').toString()
'Symbol(for each method of xxx)'
>

另一个创建符号的方式是Symbol.for,你传给它一个字符串描述,它会在全局的符号注册表(Symbol Registry)中看看,是不是有相同字符串描述的符号,如果有就返回,如果没有就使用指定的字符串作为描述创建一个新符号。

> let s1 = Symbol.for('symbol 1 for testing');
undefined
> let s = Symbol.for('symbol 1 for testing');
undefined
> s1 === s;
true
> let s2 = Symbol.for('symbol 2 for testing');
undefined
> s1 === s2;
false
>

本来是为了避免使用字符串描述来代表符号,现在又使用字符串描述来查找符号注册表,这是件很怪的事,目前看来也没别的替代方案,从另一方面来说,也应该避免使用全局符号注册表,因为它是…呃…全局嘛!若真的需要使用Symbol.for来创建新符号放在全局符号注册表,得有非常好的理由,证明它真的可以是全局适用,而且尽量指定一个独一无二的字符串,像是指定网域、组织名称作为前置文本之类的。

除了全局符号注册表之外,ES6 也有一些Symbol上的内置特性存储着符号,像是Symbol.iterator代表着迭代器符号:

> Symbol.iterator
Symbol(Symbol.iterator)
>

ES6 中如果对象有函数(方法)可返回迭代器,该函数会以Symbol.iterator符号作为特性存储,若想要获取该函数,就可以透过Symbol.iterator符号作为特性获取,例如:

> let arr = [1, 2, 3];
undefined
> let iterator = arr[Symbol.iterator]();
undefined
> iterator.next();
{ value: 1, done: false }
> iterator.next();
{ value: 2, done: false }
> iterator.next();
{ value: 3, done: false }
> iterator.next();
{ value: undefined, done: true }
>

反过来说,如果对象上打算让它有个函数(方法)可返回迭代器,在遵守 ES6 的规范下,该函数也要以Symbol.iterator符号作为特性存储,有关迭代器在这方面的细节,之后会有另一份文件介绍。

如果你有个符号,可以使用Symbol.keyFor返回它在全局符号注册表中的键,由于键就是符号的描述字符串,Symbol.keyFor实际上只是用来确定符号是否存在于全局符号注册表之中,如果返回字符串就表示有,返回undefined就表示没有,例如:

> let s1 = Symbol.for('s1 symbol');
undefined
> Symbol.keyFor(s1);
's1 symbol'
> Symbol.keyFor(Symbol.iterator);
undefined
>

更多符号的实际应用,在之后适当的文件主题之下,会再做说明。


展开阅读全文