Symbol(符号)是 ECMAScript 6 新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。
符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险

1、符号的基本用法

符号需要使用 Symbol()函数初始化。因为符号本身是原始类型,所以 typeof 操作符对符号返回 symbol。

  1. let sym = Symbol();
  2. console.log(typeof sym); // symbol

2. 使用全局符号注册表

如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册
表中创建并重用符号。
为此,需要使用 Symbol.for()方法:

  1. let fooGlobalSymbol = Symbol.for('foo');
  2. console.log(typeof fooGlobalSymbol); // symbol

Symbol.for()对每个字符串键都执行幂等操作。第一次使用某个字符串调用时,它会检查全局运 行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。后续使用相同 字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。

  1. // 使用Symbol.for前
  2. let fooGlobalSymbol = Symbol('foo');
  3. let otherFooGlobalSymbol = Symbol('foo');
  4. console.log(fooGlobalSymbol === otherFooGlobalSymbol); // false
  5. // 使用Symbol.for后
  6. let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
  7. let otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号
  8. console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
  9. // 注意:即使采用相同的符号描述,在全局注册表中定义的符号跟使用 Symbol()定义的符号也并不等同:
  10. let localSymbol = Symbol('foo');
  11. let globalSymbol = Symbol.for('foo');
  12. console.log(localSymbol === globalSymbol); // false

还可以使用 Symbol.keyFor()来查询全局注册表,这个方法接收符号,返回该全局符号对应的字
符串键。如果查询的不是全局符号,则返回 undefined。

  1. // 创建全局符号
  2. let s = Symbol.for('foo');
  3. console.log(Symbol.keyFor(s)); // foo
  4. // 创建普通符号
  5. let s2 = Symbol('bar');
  6. console.log(Symbol.keyFor(s2)); // undefined
  7. 如果传给 Symbol.keyFor()的不是符号,则该方法抛出 TypeError
  8. Symbol.keyFor(123); // TypeError: 123 is not a symbol

注意 在提到 ECMAScript 规范时,经常会引用符号在规范中的名称,前缀为@@。比如,
@@iterator 指的就是 Symbol.iterator

3、 Symbol.hasInstance

Symbol.hasInstance 操作符可以用来确定一个对象 实例的原型链上是否有原型

  1. function Foo() {}
  2. let f = new Foo();
  3. console.log(Foo[Symbol.hasInstance](f)); // true
  4. class Bar {}
  5. let b = new Bar();
  6. console.log(Bar[Symbol.hasInstance](b)); // true

4、 Symbol.isConcatSpreadable

数组对象默认情况下会被打平到已有的数组,false 或假值会导致整个对象被追加到数组末尾。类 数组对象默认情况下会被追加到数组末尾,true 或真值会导致这个类数组对象被打平到数组实例。其 他不是类数组对象的对象在 Symbol.isConcatSpreadable 被设置为 true 的情况下将被忽略

  1. let a = {
  2. age: 18,
  3. name: 'zhangsan'
  4. };
  5. a[Symbol.isConcatSpreadable] = true;
  6. let b = ['html', 'css'];
  7. let d = [1, 2, 3]
  8. d[Symbol.isConcatSpreadable] = false;
  9. console.log(d.length);
  10. let c = b.concat(d);
  11. console.log(c);
  12. //[
  13. 'html',
  14. 'css',
  15. [ 1, 2, 3, [Symbol(Symbol.isConcatSpreadable)]: false ]
  16. ]