Symbol
Symbol
  概述
    ES6 引入了一种新的原始数据类型Symbol，表示独一无二的值
    Symbol 值通过Symbol函数生成
      let s = Symbol();
typeof s
// "symbol"
    注意：不能new
    Symbol函数可以接受一个字符串作为参数，表示对 Symbol 实例的描述
    如果 Symbol 的参数是一个对象，就会调用该对象的toString方法，将其转为字符串，然后才生成一个 Symbol 值
      const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
    相同参数的Symbol函数的返回值也是不相等的
    Symbol 值不能与其他类型的值进行运算，会报错
    Symbol 值可以显式转为字符串
      let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
  Symbol.prototype.description
    ES2019 提供了一个实例属性description，直接返回 Symbol 的描述
      const sym = Symbol('foo');
sym.description // "foo"
  作为属性名的 Symbol
    Symbol值用于对象的属性名，可以保证不会出现同名的属性
      let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
      // 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
      // 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
      都得到同样结果
a[mySymbol] // "Hello!"
  注意，Symbol 值作为对象属性名时，不能用点运算符
  消除魔术字符串
    const shapeType = {
triangle: Symbol()
};
  属性名的遍历
    Symbol 作为属性名，遍历对象的时候，该属性不会出现在for...in、for...of循环中，也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回
    使用Object.getOwnPropertySymbols()方法，可以获取指定对象的所有 Symbol 属性名
  Symbol.for()
    接受一个字符串作为参数，然后搜索有没有以该参数作为名称的 Symbol 值。如果有，就返回这个 Symbol 值，否则就新建一个以该字符串为名称的 Symbol 值，并将其注册到全局。
      let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
  Symbol.keyFor()
    返回一个已登记的 Symbol 类型值的key
      let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
  内置的 Symbol 值
    Symbol.hasInstance
    Symbol.isConcatSpreadable
    Symbol.species
    Symbol.match
    Symbol.replace
    Symbol.search
    Symbol.split
    Symbol.iterator
    Symbol.toPrimitive
    Symbol.toStringTag
    Symbol.unscopables