什么是symbol
symbol是用来防止属性名冲突的,用symbol创建的变量是独一无二的
创建symbol
let a = Symbol();
typeof a//symbol
在es6中,symbol也成为了JavaScript的数据类型之一,其他六种是,undefind,null,number,string,boolean,object
symbol创建的时候也可以传入参数,但是这仅仅是他们的标识符而已,标识符相同这两个symbol并不是相同的
let a = Symbol("abc");
let b = Stmbol("abc");
a === b //false;
如果需要读取这个标识符,可以使用description
let a = Symbol("abc");
a.description() // "abc"
Symbol的作用
symbol可以用来作为对象属性的唯一标识符,当一个对象是由多个模块组成的时候,就不怕属性会被覆盖了,在用symbol作为属性的标识符的时候,不可以用点运算符,例如
let a = Symbol();
let b = {};
b.mySymbol = "hello";
b[mySymbol] //undefind;
b["mySymbol"]//"hello"
这是因为用点运算符添加的属性本质上他的属性名是字符串类型而不是symbol类型的,在对象里面定义属性的时候也要将symbol写在中括号里面
let a = Symbol();
let b = {
[a]: function(){
//somecode
}
}
例子
消除魔术字符串
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的值是无所谓的,所以,我们可以将shapeType的triangle用symbol来代替
const shapeType = {
triangle: Symbol()
};
单例模式
当我们将单例放到全局对象中的时候
// mod.js
function A() {
this.foo = 'hello';
}
if (!global._foo) {
global._foo = new A();
}
module.exports = global._foo;
加载模块
const a = require('./mod.js');
console.log(a.foo); //"hello"
这里有一点危险,因为global._foo是可写的
global._foo = { foo: 'world' };
const a = require('./mod.js');
console.log(a.foo); //"hello"
所以我们可以用在global对象上用symbol作为属性名
const FOO_KEY = Symbol.for('foo');
function A() {
this.foo = 'hello';
}
if (!global[FOO_KEY]) {
global[FOO_KEY] = new A();
}
module.exports = global[FOO_KEY];
这样,在global对象上就有一个独一无二的对象名,不怕无意和别人的属性名冲突了,要注意,是无意!但其实如果用Symbol.for来写的话还是可以被改写的。
global[Symbol.for('foo')] = { foo: 'world' };
const a = require('./mod.js');
如果想要不被改写的话,只能使用Symbol()来生成symbol了
定义一组值不会重复的常量
const COLOR_RED = Symbol();
const COLOR_GREEN = Symbol();
function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_GREEN;
case COLOR_GREEN:
return COLOR_RED;
default:
throw new Error('Undefined color');
}
}
总结
最后,symbol是不可枚举的,也就是说,for..of
for..in
Object.keys()
是不能遍历到symbol类型的值的,要得到symbol的值有两种办法,一种是使用Object.getOwnPropertySymbols
,返回一个数组包括这个对象中所有的symbol类型的值,另一种是使用Reflect.ownKeys
,可以返回常规类型的键名和symbol类型的。我个人认为,symbol就是可以生成一个永不重复的值,然后怎么使用这个值就看写程序的人了。