ES6 Symbol
在ES5中对象的属性名都是字符串稍微一不小心就会造成属性名的冲突,为了防止这个问题的出现,ES6中引入了一种新的原始数据类型Symbol,所以在ES6中我们的数据类型从原来的Number 、 String 、 Boolean 、Object、null 和 undefined六种数据类型增加到七种数据类型,增加了我们本文要讲的Symbol类型。
用法:
讲了这么多,那这个Symbol到底要怎么使用呢?下面我们就开始讲讲怎么使用这个新同志Symbol。
要创建一个Symbol类型的变量用如下操作:
let ou = Symbol("xx");//这样我们便创建了一个Symbol类型的变量。
此时我们发现这个Symbol前面并没有new命令,这是以为Symbol是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。并且相同参数Symbol()返回的值不相等。
let ou = Symbol("xx");
console.log(ou); //Symbol(xx)
let aa = Symbol("xx");
ou === aa;//false
如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
注意:Symbol 值不能与其他类型的值进行运算,会报错。
例如:
let ou = Symbol ('xx');
let a = "hello Symbol"+ou;
//TypeError: can't convert symbol to string
虽然Symbol不能与其他类型进行运算,但是Symbol可以转换为字符串与布尔值但不可转换为数值:
例如:
let ou = Symbol ('xx');
let a = ou.toString(); //Symbol(xx)
let b = Boolean(ou); //true
let c = Number(ou);//TypeError
使用Symbol
作为属性名
由于每一个Symbol的值都是不相等的,所以我们把它用作对象属性名可以保证属性名不重复。具体使用方法如下:
let sy = Symbol("key1");
// 写法1
let syObject = {};
syObject[sy] = "kk";
console.log(syObject); // {Symbol(key1): "kk"}
// 写法2
let syObject = {
[sy]: "kk"
};
console.log(syObject); // {Symbol(key1): "kk"}
// 写法3
let syObject = {};
Object.defineProperty(syObject, sy, {value: "kk"});
console.log(syObject); // {Symbol(key1): "kk"}
Symbol 作为对象属性名时不能用.运算符,要用方括号。因为.运算符后面是字符串,所以取到的是字符串 sy 属性,而不是 Symbol 值 sy 属性。
let syObject = {};
syObject[sy] = "kk";
syObject[sy]; // "kk"
syObject.sy; // undefined
注意点
Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。但是不会出现在 for…in 、 for…of 的循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回。如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
let syObject = {};
syObject[sy] = "kk";
console.log(syObject);
for (let i in syObject) {
console.log(i);
} // 无输出
Object.keys(syObject); // []
Object.getOwnPropertySymbols(syObject); // [Symbol(key1)]
Reflect.ownKeys(syObject); // [Symbol(key1)]
Symbol.for(),Symbol.keyFor()
有时,我们希望重新使用同一个 Symbol 值,Symbol.for方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
上面代码中,s1和s2都是 Symbol 值,但是它们都是同样参数的Symbol.for方法生成的,所以实际上是同一个值。
Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined