1.概述

ES6 引入了一种新的数据类型 Symbol,是 JavaScript 的第七种数据类型,前六种为:null、undefined、boolean、number、string、object。Symbol 数据类型能保证每个属性的名字是独一无二的。

Symbol 值通过 symbol 函数生成,注意此时不能用 new 来生成,这是因为 Symbol 类型是原始数据类型,不是对象类型 ,因此它也不能添加属性。基本上 Symbol 类型类似于字符串类型。

let s = Symbol();
typeof s // "symbol"

Symbol 可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时比较容易区分。

let s1 = Symbol("foo");
let s2 = Symbol("bar");

s1 // Symbol(foo)
s2 // Symbol(bar)

s1.toString();//"Symbol(foo)"
s2.toString();//"Symbol(bar)"

如果 Symbol 的参数是一个对象,则会调用对象的 toString()将其转换为字符串后才生成一个 Symbol 值。

const obj = {
   toString(){
       return "abc";
   }
};

const s = Symbol(obj);  
s  //Symbol(abc)

Symbol 函数的参数只是对当前 Symbol 值的描述,因此参数相同的 Symbol 函数的返回值是不相等的

let s1 = Symbol();
let s2 = Symbol();

s1 === s2;  //false

Symbol 值不能与其他类型的值进行运算,否则会报错

let s = Symbol("hello");

s + "world";  //TypeError:cannot convert symbol to string
'${s} world';  //TypeError:cannot convert symbol to string

Symbol 值除了可以用 toString() 转换为字符串外,还可用用 Boolean(变量名) 转为布尔类型,但是不能转为数值类型。

2. Symbol.prototype.description :直接返回 Symbol 的描述

let s = Symbol("foo");

s.description  //"foo"

3. 作为对象的属性名

由于每一个 Symbol值都是不相等的,故其可以当做标识符,用于对象的属性名,就保证不会出现同名的属性。Symbol 作为属性名时,不能用点运算符。作为属性名,Symbol 为公开属性,不是私有属性。

//例1
let sym = Symbol();

//第一种写法
let a = {};
a[sym] = "hello";

//第二种写法
let a = {
   [sym] = "hello";
};

//第三种写法
let a = {};
Object.defineProperty(a,sym,{value:"hello"});

//以上都会得到一样的结果
a[sym]  //"hello"

//例2
let sym = Symbol();
let obj = {
   [sym]:function(args){...}  // 还可以这么写  [sym](args){...}
};

obj[sym](123);

4. 属性名的遍历Object.getOwnPropertySymbols() 返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。Reflect.ownKeys() 可以返回任何类型的属性名。

5. Symbol.for(),Symbol.keyFor()

Symbol.for():有时我们需要用到同一个 Symbol 值,Symbol.for() 可以做到这一点。它接受一个字符串为参数,然后搜索有没有以该参数名作为属性名的 Symbol 值。若有,就返回这个 Symbol 值,否则就新建一个以这个参数名作为属性名的 Symbol 值,并将其注册到全局。注意,Symbol.for() 为 Symbol 值登记的名字,是全局环境的,不管其有没有在全局环境中运行。

let s1 = Symbol.for();
let s2 = Symbol.for();

s1 === s2 //true

Symbol.keyFor():返回一个已登记的 Symbol 类型的 key。

let s1 = Symbol.for("foo");
Symbol.keyFor(s1)  //"foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2)  //undefined  因为 s2 未登记