ES5 的对象属性名都是字符串,这容易造成属性名的冲突
比如,我们使用了一个他人提供的对象,
但又想为这个对象添加新的方法Cmixin 模式〉,
新方法的名字就有可能与现有方法产生冲突。
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值
是第七种数据类型
1.Number
2.String
3.Undefined
4.Null
5.Boolean
6.Object
Symbol值是通过Symbol函数生成,
只要属性名属于Symbol类型,就是独一无二的,
可以保证不会与其他属性名冲突
let s1 = Symbol();
console.log(typeof s1);
PS:Symbol函数不能使用new命令,
因为生成的Symbol是一个原始类型的值,不是对象
就是说Symbol不是对象,所以不能添加属性
基本上,他是一种类似于字符串的数据类型
// Symbol添加参数,便于区分
let s2 = Symbol('foo');
let s3 = Symbol('bar');
console.log(s2,s3);
// eg1
let mySymbol = Symbol();
let mySymbol2 = Symbol();
let mySymbol3 = Symbol();
// 第一种写法
let a = {};
a = {
[mySymbol2] : 'world'
}
// 第二种写法
a[mySymbol] = 'hello';
// 第三种写法 不太行
Object.defineProperty(a,mySymbol3,{value : 'wjy'});
console.log(a)
Symbol类型还可以用于定义一组变量,保证这组变量的值都不相等
/*
log.levels = {
DEBUG : Symbol('debug'),
INFO : Symbol('info'),
WARN : Symbol('warn')
};
log(log.levels.DEBUG,'debug message');
*/
// 例子:消除魔术字符串
function getArea(shape,options){
let area = 0;
switch(shape){
case 'Triangle': //魔术字符串
area = .5 * options.width * options.height;
break;
default:
area = "false";
break;
}
return area;
}
强耦合
console.log(getArea('Triangle',{width : 100,height : 200}));
// change
function getAreaChange(shape,options){
let area = 0;
let { PI } = Math;
switch(shape){
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
case shapeType.circle:
area = PI * options.radius ** 2;
break;
default:
area = "false";
break;
}
return area;
}
let shapeType = {
// triangle : 'Triangle'
/*
经过分析可知,shapeType.triangle等于哪个值不重要
只要确保不会和其他shapeType属性的值冲突即可
*/
triangle : Symbol(),
circle : Symbol()
};
console.log(getAreaChange(shapeType.triangle,{ width : 200, height : 3}));
console.log(getAreaChange(shapeType.circle,{ radius : 2 }));
属性名的遍历
let { getOwnPropertyNames , getOwnPropertySymbols , defineProperty } = Object;
let objectSymbols1 = getOwnPropertySymbols(a);
console.log(objectSymbols1)
// another example
let obj3 = {};
let foo3 = Symbol("foo");
defineProperty(obj3,foo3,{
value : "foobar",
});
for(let i in obj3){
console.log(i); //无输出
}
使用getOwnPropertyNames方法得不到Symbol属性名
需要使用getOwnPropertySymbols方法
console.log(getOwnPropertyNames(obj3));
console.log(getOwnPropertySymbols(obj3));
可以使用Reflect.ownKeys()方法返回所有类型的键名
包括常规键名和Symbol键名
const { ownKeys } = Reflect;
let obj4 = {
[Symbol('my_key')]: 1,
enum : 2,
nonEnum : 3
};
console.log(ownKeys(obj4));
以Symbol值作为名称的属性不会被常规方法遍历得到。
我们可以利用这个特性为对象定义些非私有但又希望只用于内部的方法。
let size = Symbol('size');
class Collection{
constructor(){
this[size] = 0;
}
add(item){
this[this[size]] = item;
this[size]++;
}
static sizeOf(instance){
return instance[size];
}
}
let x = new Collection();
console.log(Collection.sizeOf(x));
x.add('foo');
console.log(Collection.sizeOf(x))
const { keys , getOwnPropertySymbols , getOwnPropertyNames } = Object;
console.log(keys(x),getOwnPropertyNames(x),getOwnPropertySymbols(x));