1、概述
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。于是,ES6 引入 了一种新的原始数据类型 Symbol
来保证每个属性的名字是独一无二的,从而解决了属性名冲突问题。
ES6 引入 Symbol 后 JavaScript 就有了七种数据类型:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)、Symbol 。
Symbol 值是通过 Symbol
函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种是新增的 Symbol 类型。
Symbol
函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述。
var s = Symbol();
typeof s => Symbol
var s1 = Symbol('foo');
s1 => Symbol(foo)
注意:
(1)Symbol
函数前不能使用 new
命令,否则会报错。这是因为 Symbol 是一个原始数据类型,不是对象。
(2)如果 Symbol 的参数是一个对象,就会调用该对象的 toString
方法,将其转为字符串,然后生成一个 Symbol 值。默认的 toString
方法返回的是 [Object Object]
。
(3)Symbol
函数的参数只是表示当前 Symbol 值的描述,因此相同参数的 Symbol
函数返回值是不相等的。
var s1 = Symbol();
var s2 = Symbol();
console.log(s1 == s2); => false
console.log(s1 === s2); => false
(4)Symbol 值不能与其他类型的值进行运算,会报错。
(5)Symbol 值可以显示转为字符串。Symbol 值也可以转为布尔值(不管 Symbol 实例是否有描述,都返回 true
),但是不能转为数值。
var s3 = Symbol('3');
String(s3); => Symbol(3)
s3.toString(); => Symbol(3)
Boolean(s3); => true
!s3; -=> false
Number(s3); => 报错
s3 + 2; => 报错,不能与其他类型值进行运算
2、作为属性名的 Symbol
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名属性。
var mySymbol = Symbol();
--------------------------------------
var a = {};
a[mySymbol] = 'Hello';
--------------------------------------
var a ={
[mySymbol]: 'Hello'
};
--------------------------------------
var a = {};
Object.defineProperty(a, mySymbol, {value: 'Hello'});
--------------------------------------
a[mySymbol] => 'Hello'
注意:Symbol 值作为对象属性名时,不能用点运算符,因为点运算符后面总是字符串。同理,在对象内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号内。
3、Symbol 属性名的遍历
Symbol 作为属性名,该属性不会出现在 for...in
、 for...of
循环中,也不会被 Object.keys()
、 Object.getOwnPropertyNames()
、 JSON.stringify()
返回。但是,它也不是私有属性,有一个 Object.getOwnPropertySymbol
方法,可以获取指定对象的所有 Symbol 属性名。
另一个新的 API,Reflect.ownKeys
方法可以返回所有类型的健名,包括常规健名和 Symbol 健名。
由于 Symbol 值作为属性名,不会被常规方法遍历到,可以借助该特性为对象定义一些非私有属性,但又希望只有用于内部的方法。
4、Symbol.for() Symbol.keyFor()
Symbol.for()
方法接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
注意:Symbol.for()
和 Symbol()
都会返回新生成的 Symbol。区别在于,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()
为 Symbol 值登记的名字,是全局环境的。
var s1 = Symbol('foo');
var s2 = Symbol('foo');
var s3 = Symbol.for('foo');
var s4 = Symbol.for('foo');
s1 === s2 => false
s3 === s4 => true
s1 === s3 => false
Symbol.keyFor()
方法返回一个已登记的 Symbol 类型值的 key
。