在ES5中,对象的属性名都是字符串,这容易造成属性名的冲突(比如,在模块化应用中,如果你使用了一个其他人提供的对象,同时你又想为这个对象添加新的属性,这个新的属性的名字,就有可能和原来的对象中的属性名发生冲突,导致覆盖产生(结果把原模块的对象中的’a’属性的值覆盖了),如下例:
let obj = {a: 'a'} // 引用其他模块的对象
obj['a'] = 'b' // 想添加一个'a'属性
console.log(obj); // {a: 'b'}
如果存在一种机制,保证每个属性的名字都是独一无二的,这样就能够防止属性的冲突了。于是在 ES6
引入 Symbol
。
1、Symbol()
Symbol
和 Undefined、Null、Boolean、String、Symbol、Number
类型一样,都属于原始数据类型。Symbol
通过Symbol
函数生成(注意:Symbol
为原始数据类型,不能使用new
命令)
let s1 = Symbol()
let s2 = Symbol()
console.log(typeof s1); //symbol
console.log(s1 === s2); //false
2、Symbol()的参数
Symbol
函数也可以接收一个字符串作为参数,表示对Symbol
实例的描述,这样做的目的是利于区分:
注意:Symbol
()的参数只是表示对于当前Symbol
值得描述,因此相同参数的Symbol
的返回值是不相等的
//s1和s2都是Symbol值,如果不加参数,它们的输出都是Symbol,不利于区分
let s1 = Symbol()
let s2 = Symbol()
console.log(s1)//Symbol
console.log(s2)//Symbol
//参数只是一种描述,相同参数时,两个Symbol()的返回值并不相等
let s3 = Symbol('foo')
let S4 = Symbol('foo')
console.log(s3)//Symbol(foo)
console.log(s4)//Symbol(foo)
console.log(s3 === s4)//false
3、Symbol作为对象中的属性名
ES6
引入Symbol
后,对象中的属性名现在可以有两种,一种是本来就有的字符串,另一种则是新增的Symbol
类型。由于每个Symbol
值都是不同的,这就意味着,当一个对象由模块构成时,就能够发防止莫一个键被不小心改写或覆盖
let obj = {a: 'a'}
let a = Symbol()
obj[a] = 'b'
console.log(obj); // {a: 'a', Symbol(): 'b'}
注意:Symbol
值作为对象属性时,不能使用点运算符,因为点运算符后面接的是字符串。只能使用中括号,因为中括号内接表达式
let obj = {a: 'a'}
let a = Symbol()
obj[a] = 'b'
console.log(obj.a) // a
console.log(obj[a]) // b
4、属性名的遍历
Symbol
作为属性名,该属性不会出现在 for…in
、 for…of
循环中,也不会被 Object.keys()
、 Object.getOwnPropertyNames()
、 JSON.stringify()
返回。但是,它也不是私有属性,有一个 Object.getOwnPropertySymbols
方法,可以获取指定对象的所有Symbol
属性名(以数组形式排列)
let obj = {a: 'js'}
let a = Symbol()
obj[a] = 'es'
for (const key in obj) {
console.log(key); // a
}
for (const key of Object.getOwnPropertyNames(obj)) {
console.log(key); // a
}
for (const key of Object.keys(obj)) {
console.log(key); // a
}
console.log(JSON.stringify(obj)) // {"a":"js"}
5、Symbol.for()
我们希望重新使用同一个 Symbol
值, Symbol.for
方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol
值。如果有,就返回这个Symbol
值,否则就新建并返回一个以该字符串为名称的 Symbol
值
let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1===s2) // true
6、Symbol()和Symbol.for()的区别、以及Symbol.keyfor()
Symbol()
每次被调用都会生成一个新的Symbol
(一位内Symbol(写法没有登记机制,所以每次调用都会返回一个不同的值)Symbol.for()
不会每次调用就返回一个新的Symbol
,而是会先检查给定的key
是否已经存在,如果不存在,则会在全局创建并注册这个key
,然后才会新建一个Symbol
值Symbol.keyFor()
方法返回一个已经登记的Symbol
类型值的key
let s1 = Symbol.for("foo");
console.log(Symbol.keyFor(s1)); // "foo"
let s2 = Symbol("foo");
console.log(Symbol.keyFor(s2)); // undefined
7、内置的Symbol值