Symbol(符号)是 ECMAScript 6 新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。
符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险
1、符号的基本用法
符号需要使用 Symbol()函数初始化。因为符号本身是原始类型,所以 typeof 操作符对符号返回 symbol。
let sym = Symbol();
console.log(typeof sym); // symbol
2. 使用全局符号注册表
如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册
表中创建并重用符号。
为此,需要使用 Symbol.for()方法:
let fooGlobalSymbol = Symbol.for('foo');
console.log(typeof fooGlobalSymbol); // symbol
Symbol.for()对每个字符串键都执行幂等操作。第一次使用某个字符串调用时,它会检查全局运 行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。后续使用相同 字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
// 使用Symbol.for前
let fooGlobalSymbol = Symbol('foo');
let otherFooGlobalSymbol = Symbol('foo');
console.log(fooGlobalSymbol === otherFooGlobalSymbol); // false
// 使用Symbol.for后
let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
let otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号
console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
// 注意:即使采用相同的符号描述,在全局注册表中定义的符号跟使用 Symbol()定义的符号也并不等同:
let localSymbol = Symbol('foo');
let globalSymbol = Symbol.for('foo');
console.log(localSymbol === globalSymbol); // false
还可以使用 Symbol.keyFor()来查询全局注册表,这个方法接收符号,返回该全局符号对应的字
符串键。如果查询的不是全局符号,则返回 undefined。
// 创建全局符号
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s)); // foo
// 创建普通符号
let s2 = Symbol('bar');
console.log(Symbol.keyFor(s2)); // undefined
如果传给 Symbol.keyFor()的不是符号,则该方法抛出 TypeError:
Symbol.keyFor(123); // TypeError: 123 is not a symbol
注意 在提到 ECMAScript 规范时,经常会引用符号在规范中的名称,前缀为@@。比如,
@@iterator 指的就是 Symbol.iterator
3、 Symbol.hasInstance
Symbol.hasInstance 操作符可以用来确定一个对象 实例的原型链上是否有原型
function Foo() {}
let f = new Foo();
console.log(Foo[Symbol.hasInstance](f)); // true
class Bar {}
let b = new Bar();
console.log(Bar[Symbol.hasInstance](b)); // true
4、 Symbol.isConcatSpreadable
数组对象默认情况下会被打平到已有的数组,false 或假值会导致整个对象被追加到数组末尾。类 数组对象默认情况下会被追加到数组末尾,true 或真值会导致这个类数组对象被打平到数组实例。其 他不是类数组对象的对象在 Symbol.isConcatSpreadable 被设置为 true 的情况下将被忽略
let a = {
age: 18,
name: 'zhangsan'
};
a[Symbol.isConcatSpreadable] = true;
let b = ['html', 'css'];
let d = [1, 2, 3]
d[Symbol.isConcatSpreadable] = false;
console.log(d.length);
let c = b.concat(d);
console.log(c);
//[
'html',
'css',
[ 1, 2, 3, [Symbol(Symbol.isConcatSpreadable)]: false ]
]