简介
大家都知道,ES5的对象的属性名都是字符串,这样就很容易造成属性名冲突,从而替代了原有对象的方法,于是,ES6就提供了Symbol,表示独一无二的值,它是一种新的原始数据类型,symbol类型。
注意哦!Symbol是基本数据类型,所以不能使用new命令,否则会报错。
基本用法
let s1 = Symbol([1,2]);
let s2 = Symbol('bar');
console.log(s1) // Symbol(1,2)
console.log(s2) // Symbol(bar)
这里可以看到,Symbol是可以接受一个字符串作为参数的,仅用来对Symbol实例的描述。
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
以上代码,就可以很明显的看出来,参数只是它的描述,另外需要注意的是,如果传入的参数是一个对象的话(无论是数组对象还是咱们口中的对象),它都会执行对象的toString()方法,如下所示。
let s1 = Symbol({a:1});
let s2 = Symbol([1,2]);
let s3=Symbol({toString:()=>2})
console.log(s1)//Symbol([object Object])
console.log(s2)//Symbol(1,2)
console.log(s3)//Symbol(2)
还需要注意的是,Symbol不允许和其他数据类型的值进行运算,否则会报错,但是可以显示的转为字符串或者布尔值。
作为属性名使用时
作为属性名使用时不能用点形式,必须放在方括号内,如果用点,声明的是普通属性名,并不是Symbol,如下代码所示:
let mySymbol = Symbol();
let a = {};
a.mySymbol="yes"
a[mySymbol] = 'Hello!';
console.log(a["mySymbol"])//yes
console.log(a[mySymbol])//hello
需要注意的是,作为属性名使用时,是不会被for...in、for...of、Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()
返回的,但他并不是私有属性,用Object.getOwnPropertySymbols()
这个方法,可以获取到所有的Symbol属性名,还有一个新API,就是Reflect.ownKeys
,它返回所有键值,包括常规属性。
let mySymbol= Symbol(1)
let a={
[mySymbol]:1,
name:2
}
for(let i in a){
console.log(i+"in")
}
//namein
for(let i of Object.keys(a)){
console.log(i+"Object.keys")
}
//nameObject.keys
for(let i of Reflect.ownKeys(a)){
console.log(i)
}
//name Symbol(1)
for(let i of Object.getOwnPropertySymbols(a)){
console.log(i)
}
//Symbol(1)
但是,我们可以利用这一特点,为对象设置一些即没暴漏出去,又再内部能使用的方法。
let size = Symbol('size');
class Collection {
constructor() {
this[size] = 0;
this.x = 1
}
add() {
this[size]++;
}
sizeOf() {
return this[size];
}
}
let x = new Collection();
x.add()
console.log(x.sizeOf())//1
console.log(Object.keys(x)) // ['x']
console.log(Object.getOwnPropertyNames(x)) // ['x']
console.log(Object.getOwnPropertySymbols(x)) // [Symbol(size)]
上面代码可以看出,当调用x.add()方法后,内部Symbol值size是改变了,但是类外部,是访问不到实例属性的。
symbol.for和symbol.keyFor
Symbol.for可以使用相同的Symbol的值,它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined