1. 关于Symbol
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin
模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol
的原因。
ES6 引入了一种新的原始数据类型Symbol
,表示独一无二的值。它是 JavaScript
语言的第七种数据类型。
现在对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol
类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
2. 使用Symnol的注意事项
Symbol
值通过Symbol
函数生成。值得注意的是,Symbol
函数前不能使用new
命令,否则会报错,因为Symbol
是一种原始数据类型,所以Synbol
函数并非构造函数,生成的Symbol
值也不能添加属性。
另外,Symbol
函数可以接受一个字符串作为参数,表示对Symbol
实例的描述,主要是为了方便我们区分。
const sym1 = Symbol('a')
const sym2 = Symbol('b')
typeof sym1 // "symbol"
sym1 // Symbol(a)
sym2 // Symbol(b)
2.1 如果接受的参数是对象
如果Symbol
函数接受的参数是一个对象,那么会先调用对象的toString
方法将其转为字符串,然后生成一个Symbol
值。
const obj = {
toString () {
return 'test'
}
}
const obj1 = {name: 'bing'}
let test = Symbol(obj)
let test1 = Symbol(obj1)
test // Symbol(test)
test1 // Symbol([object Object])
从上述代码我们可以发现,当我们使用Symbol
函数时需要避免传入参数是对象。
2.2 每一个Symbol值都是独一无二的
在关于Symbol
中我们讲了每一个Symbol
值都是独一无二的,尽管我们使用Symbol
函数接受相同的参数,但是生成的值仍然不相等。
let s1 = Symbol(1)
let s2 = Symbol(1)
s1 === s2 // false
值得注意的是Symbol
值不能与其他类型的值进行运算,会报错,但是Symbol
也可以转为布尔值和字符串,但是不能转为数值。
let symbol = Symbol(1)
symbol + 1 // TypeError: Cannot convert a Symbol value to a number
Boolean(symbol) // true
symbol.toString() // "Symbol(1)"
2.3 实例方法Symbol.prototype.description
创建Symbol
值的时候,函数接受的参数就是这个值的描述,通过Symbol.prototype.description
方法可以直接返回Symbol
的描述。
const sym = Symbol('a')
sym.description // "a"
3. Symbol当做属性名
由于每一个 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
值作为属性名时,该属性还是公开属性,不是私有属性。
4. Symbol属性名的遍历
Symbol
作为属性名,该属性不会出现在for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols
方法,可以获取指定对象的所有 Symbol
属性名。
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]