目录
前言
ES6引入的一种新的原始数据类型Symbol,表示独一无二的值。Symbol函数可以接受参数,表示对于这个唯一值的描述,属于基本数据类型,Symbol()函数会返回symbol类型的值。
一、创建Symbol值
Symbol是一个函数,不需要使用new关键字来创建
let sy1 = Symbol();
console.log(sy1); //Symbol()
console.log(typeof sy1); //symbol
Symbol函数还可以接收参数:
let sy1 = Symbol('hello');
console.log(sy1); //Symbol(hello)
console.log(typeof sy1); //symbol
Symbol表示独一无二的值,即使取一样的参数,两个变量也不相等
let sy1 = Symbol('hello')
let sy2 = Symbol('hello')
console.log(sy1 === sy2); //false
二、Symbol数据类型的作用
1、解决命名冲突
例子:
当我们想要给一个对象添加新属性时,如果我们担心属性名重名,就可以使用Symbol数据类型。
// 声明两个Symbol类型的变量
let sy1 = Symbol('name');
let sy2 = Symbol('age');
let obj = {
name: "zhangsan",
age: 12,
// 属性名是变量名时使用中括号
[sy1]: 'lisi',
[sy2]: 18,
[Symbol('email')]: '888888@qq.com'
};
// 访问方式,用中括号访问
console.log(obj[sy1]); //lisi
console.log(obj[sy2]); //18
console.log(obj[Symbol('email')]); //undefined
注意:当属性名是变量时,我们需要使用中括号括起来。
访问方式也是直接使用中括号访问。
上述代码,我们可以使用中括号访问到sy1和sy2,但是访问不到 [Symbol('email')],这时候我们可以通过Object.getOwnPropertySymbols()方法来访问该属性值,该方法返回一个包含给定对象所有自有的Symbol值的属性(包括不可枚举的Symbol值属性)组成的数组。
let res = Object.getOwnPropertySymbols(obj)
console.log(res); //[ Symbol(name), Symbol(age), Symbol(email) ]
console.log(obj[res[2]]); //888888@qq.com
注意:使用for...in循环访问不到symbol值
for(let key in obj){
console.log(key);
}
输出结果:
name
age
总结:
1、for in循环访问不到symbol值
2、获取symbol变量/值,使用getOwnPropertySymbols方法
3、如何访问属性对应属性值 obj[res[1]]
2、消除魔术字符串
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。
例子:
我们封装一个求各种图形的面积的函数,代码如下所示:
function test(shape, options) {
let area = 0;
switch (shape) {
case 'triangle':
area = .5 * options.width * options.height;
break;
case 'square':
area = options.width * options.height;
break;
case 'circle':
area = Math.PI * Math.pow(options.r, 2);
break;
default:
area = -1;
}
return area
}
console.log(test('triangle', {width: 100, height: 100, r: 100}));
可以看到代码中多次出现了具体的字符串,但我们改变函数中的字符串时,那么调用函数时的实参也需要做出改变,这样并不方便,而且如果我们要求更多图形的面积,那么我们命名的字符串很有可能会发生重复,这样调用函数就会得到错误的结果。
因此我们最好使用变量替代这些字符串:
function test(shape, options) {
let area = 0;
switch (shape) {
case Shape.triangle:
area = .5 * options.width * options.height;
break;
case Shape.square:
area = options.width * options.height;
break;
case Shape.circle:
area = Math.PI * Math.pow(options.r, 2);
break;
default:
area = -1;
}
return area
}
let Shape = {
triangle: Symbol('三角形'),
square: Symbol('三角形'),
circle: Symbol('圆形')
}
console.log(test(Shape.triangle, {width: 100, height: 100, r: 100}));
三、全局注册表
与Symbol() 不同的是,用 Symbol.for() 方法创建的 symbol 会被放入一个全局 symbol 注册表中。Symbol.for() 并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。假如是,则会直接返回上次存储的那个。否则,它会再新建一个。
例子:
不使用Symbol.for() 方法:
let sy1 = Symbol('one');
let sy2 = Symbol('one');
console.log(sy1 === sy2); //false
使用Symbol.for() 方法:
let sy1 = Symbol.for('one');
let sy2 = Symbol.for('one');
console.log(sy1 === sy2); //true
我们可以使用Symbol.keyFor()方法检测symbol值是否在全局注册表中注册过。返回对于symbol的描述或者undefined
let sy1 = Symbol.for('hello');
console.log(Symbol.keyFor(sy1)); //hello
let sy2 = Symbol('world');
console.log(Symbol.keyFor(sy2)) //undefined