一、Symbol.for实战
在JavaScript中,一个Symbol可以表示一个独一无二的标识符。在ES6中,引入了一个新的方法Symbol.for()
,它允许我们通过字符串来获取Symbol类型的值,如果该字符串不存在,则会新建一个Symbol值。
const mySymbol = Symbol.for('mySymbol');
const anotherSymbol = Symbol.for('mySymbol');
console.log(mySymbol === anotherSymbol); // true
这里通过两次调用Symbol.for('mySymbol')
分别获取了两个Symbol值,但由于它们的参数字符串相同,所以它们是同一个Symbol值。我们可以将Symbol.for()
和对象的属性结合起来使用:
const myObject = {
[Symbol.for('name')]: '张三',
[Symbol.for('age')]: 18
};
console.log(myObject[Symbol.for('name')]); // 张三
console.log(myObject[Symbol.for('age')]); // 18
在这里,我们为对象动态添加了两个Symbol类型的属性name
和age
,只能用Symbol.for()
来获取它们的值,这保证了它们是独一无二的,不会与其他属性名冲突。
二、Symbol.forget
一旦使用Symbol.for()
新建了一个Symbol值,我们就可以通过它来获取到这个Symbol值了。但在某些情况下,我们可能需要删除这个Symbol值,也就是将其从全局Symbol注册表中删除,这时可以使用Symbol.keyFor()
方法来获取其对应的键名并进行删除。
const mySymbol = Symbol.for('mySymbol');
console.log(Symbol.keyFor(mySymbol)); // 'mySymbol'
Symbol.for('mySymbol');
console.log(Symbol.keyFor(mySymbol)); // 'mySymbol'
Symbol.for('anotherSymbol');
console.log(Symbol.keyFor(mySymbol)); // undefined
以上代码中,我们使用Symbol.for()
新建了两个Symbol值,它们的参数值分别为'mySymbol'
和'anotherSymbol'
。第一次调用Symbol.keyFor()
方法可以获取到参数值为'mySymbol'
的Symbol值的键名,即'mySymbol'
,第二次调用结果仍是'mySymbol'
,因为之前已经将其注册过了,第三次调用后返回undefined
,因为我们并没有从注册表中获取到'anotherSymbol'
对应的Symbol值。
三、Symbol.for和Symbol
ES6还引入了Symbol()
方法来创建Symbol值,这个方法与Symbol.for()
很相似,区别在于Symbol()
创建的Symbol值是局部可见的,而Symbol.for()
创建的Symbol值是全局可见的。
const mySymbol1 = Symbol('mySymbol');
const mySymbol2 = Symbol('mySymbol');
console.log(mySymbol1 === mySymbol2); // false
const myGlobalSymbol1 = Symbol.for('mySymbol');
const myGlobalSymbol2 = Symbol.for('mySymbol');
console.log(myGlobalSymbol1 === myGlobalSymbol2); // true
在以上代码中,我们已经看到了Symbol()
和Symbol.for()
方法的差别。使用Symbol()
创建的Symbol值,在不同的位置上使用相同的参数值,也不能得到同一个Symbol值,它们是完全独立的。而使用Symbol.for()
创建的Symbol值,只要在全局Symbol注册表中存在同名的Symbol值,就可以得到同一个Symbol值。
四、Symbol作为对象属性名
在对象字面量中,我们通常使用字符串作为属性名,但这可能会导致属性名冲突,因此ES6引入了Symbol类型的属性名。这种属性名不会出现在for...in
循环、Object.keys()
、Object.getOwnPropertyNames()
等方法中,也只能通过Object.getOwnPropertySymbols()
方法获取到。
const myObject = {
[Symbol.for('name')]: '张三',
age: 18
};
console.log(Object.getOwnPropertySymbols(myObject)); // [Symbol(name)]
在以上代码中,我们可以看到myObject
对象中只有一个Symbol类型的属性名,可以通过Object.getOwnPropertySymbols()
方法获取到这个属性名。
五、Symbol在枚举中的应用
枚举类型是一种常用的数据类型,在ES6之前,我们都是使用对象字面量来实现枚举:
const Colors = {
RED: 0,
GREEN: 1,
BLUE: 2
};
console.log(Colors.RED); // 0
使用对象字面量可以很方便地实现枚举,但它有一个缺点:它不能保证枚举值的唯一性。因此,在ES6中推荐使用Symbol类型来实现枚举,从而达到保证唯一性的目的。
const Colors = {
RED: Symbol('RED'),
GREEN: Symbol('GREEN'),
BLUE: Symbol('BLUE')
};
console.log(Colors.RED); // Symbol(RED)
在以上代码中,我们使用Symbol()
方法创建了三个唯一的Symbol值,用它们来作为枚举类型的值,从而达到保证唯一性的目的。