Symbol是ES6中定义的一种独一无二的值,通过Symbol()
函数生成。
let s = Symbol();
typeof s
// "symbol"
因为生成的 Symbol 是一个原始类型的值,不是对象,所以Symbol函数前不能使用new命令,否则会报错。也就是说,由于 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()
函数生成的值也并不会相同
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
Symbol值可以转换为布尔值但不能转换为数值
let sym = Symbol();
Boolean(sym) // true
!sym // false
if (sym) {
// ...
}
Number(sym) // TypeError
sym + 2 // TypeError
魔术字符串
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle': // 魔术字符串
area = .5 * options.width * options.height;
break;
/* ... more code ... */
}
return area;
}
getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
上面的代码中,字符串Triangle为一个魔术字符串,与代码形成强耦合,为了维护,最好把他写成一个值而不是一个字符串,
const shapeType = {
triangle: 'Triangle'
};
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
}
return area;
}
getArea(shapeType.triangle, { width: 100, height: 100 });
但是我们发现,shapeType.triangle
值为多少并不重要,我们只要知道它表示要计算三角形面积即可,所以这时,它完全可以写成一个Symbol
const shapeType = {
triangle: Symbol()
};
Object.getOwnPropertySymbols
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)]
Reflect.ownKeys
Reflect.ownKeys
方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
Symbol.for()
Symbol.for
接受一个字符串作为参数,他会去搜索有没有以这个参数作为参数的Symbol值。若有则返回这个值,若无则重新生成此值。
let s1 = Symbol.for('foo'); // 没有此值,生成
let s2 = Symbol.for('foo'); // 发现上行代码生成的值
s1 === s2 // true
参考
《ES6标准入门》