一、什么是 Symbol
Symbol 是 ES6 新出的一种数据类型,可以简单理解为 唯一的量,独一无二的值。
symbol: 记号,标记;被标记过了,可不就唯一了嘛。
二、为什么会有 Symbol
ES5的对象的属性名都是字符串,这样很容易造成命名冲突,可能会重写原有对象的属性或者方法。
于是,就新搞出了一种新的数据类型——Symbol。
它是一种基本数据类型,不能使用 new 命令。
三、基本用法
let s1 = Symbol([1,2]);
let s2 = Symbol('bar');
console.log(s1)
console.log(s2)
Symbol 是可以接受一个字符串作为参数的,仅用来对 Symbol 实例进行描述。
let s3 = Symbol('foo');
let s4 = Symbol('foo');
s3 === s4 // false
参数只是描述,另外,如果传入的参数是一个对象的话(无论是数组对象,还是object对象),会执行对象的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