ES6 语法,表示唯一且不可变的值,常用作属性键值或者唯一标识符。
let a = Symbol()
let a = Symbol('atomic symbol')console.log(Symbol() === Symbol()) // false
console.log(Symbol('atom') === Symbol('atom')) // false
Symbol 作为属性名
let key = Symbol();
let obj = {[key]: "朝阳",
};
-
Symbol 类型值作为属性名,这个属性不会被
for…in
遍历到,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
获取到; -
可以使用
Object.getOwnPropertySymbols
方法获取对象的所有symbol类型的属性名;const name1 = Symbol("name"); const obj = {[name1]: "toimc",age: 18 }; const SymbolPropNames = Object.getOwnPropertySymbols(obj); console.log(SymbolPropNames); // [ Symbol(name) ]
-
可以用 ES6 新提供的 Reflect 对象的静态方法
Reflect.ownKeys
,它可以返回所有类型的属性名:console.log(Reflect.ownKeys(obj)); // ["age", Symbol(name)]
静态方法for 和 keyFor
使用 Symbol.for方法传入字符串,会先检查有没有使用该字符串调用 Symbol.for 方法创建的 symbol 值,如果有,返回该值,如果没有,则使用该字符串新创建一个
const s1 = Symbol("toimc");
const s2 = Symbol("toimc");
const s3 = Symbol.for("toimc");
const s4 = Symbol.for("toimc");console.log(s3 === s4) // true
console.log(s1 === s3) // false
Symbol.keyFor 方法传入一个 symbol 值,返回该值在全局注册的键名:
const sym = Symbol.for("toimc");
console.log(Symbol.keyFor(sym)); // 'toimc'
内置的 Symbol 值
ES6 提供了 11 个内置的 Symbol 值:
Symbol.hasInstance
当其他对象使用 instanceof 判断是否为这个对象的实例时,会调用你定义的这个方法
const obj = {[Symbol.hasInstance](otherObj) {console.log(otherObj);}
};
console.log({ a: "a" } instanceof obj); // false
Symbol.isConcatSpreadable
当一个数组的 Symbol.isConcatSpreadable 设为 true 时,这个数组在数组的 concat 方法中不会被扁平化。
let arr = [1, 2];
console.log([].concat(arr, [3, 4])); // 打印结果为[1, 2, 3, 4],length为4
let arr1 = ["a", "b"];
console.log(arr1[Symbol.isConcatSpreadable]); // undefined
arr1[Symbol.isConcatSpreadable] = false;
console.log(arr1[Symbol.isConcatSpreadable]); // false
console.log([].concat(arr1, [3, 4])); // [ ["a", "b", Symbol(Symbol.isConcatSpreadable): false], 3, 4 ]
Symbol.species
class C extends Array {getName() {return "toimc";}
}
const c = new C(1, 2, 3);
const a = c.map(item => item + 1);
console.log(a); // [2, 3, 4]
console.log(a instanceof C); // true
console.log(a instanceof Array); // true
console.log(a.getName()); // "toimc"
这个例子中,a 是由 c 通过 map 方法衍生出来的,我们也看到了,a 既是 C 的实例,也是 Array 的实例。但是如果我们想只让衍生的数组是 Array 的实例,就需要用 Symbol.species,我们来看下怎么使用:
class C extends Array {// 关键代码:static get [Symbol.species]() {return Array;}getName() {return "toimc";}
}
const c = new C(1, 2, 3);
const a = c.map(item => item + 1);
console.log(a); // [2, 3, 4]
// 这里是false
console.log(a instanceof C); // false
console.log(a instanceof Array); // true
console.log(a.getName()); // error a.getName is not a function
就是给类 C 定义一个静态 get 存取器方法,方法名为 Symbol.species,然后在这个方法中返回要构造衍生数组的构造函数。所以最后我们看到,a instanceof C为 false,也就是 a 不再是 C 的实例,也无法调用继承自 C 的方法。
Symbol.match
当在字符串 str 上调用 match 方法时,会调用这个方法
let obj = {[Symbol.match](string) {return string.length;}
};
console.log("abcde".match(obj)); // 5
Symbol.replace
当在字符串 str 上调用 replace 方法时,会调用这个方法,同上
Symbol.search
当在字符串 str 上调用 search方法时,会调用这个方法,同上
Symbol.split
当在字符串 str 上调用 split 方法时,会调用这个方法,同上
Symbol.iterator
数组的 Symbol.iterator 属性指向该数组的默认遍历器方法:
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
console.log(iterator);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
Symbol.toPrimitive
对象的这个属性指向一个方法,当这个对象被转为原始类型值时会调用这个方法。
这个方法有一个参数,即是这个对象被转为的类型,我们来看下:
let obj = {[Symbol.toPrimitive](type) {console.log(type);}
};
// const b = obj++ // number
const a = `abc${obj}`; // string
Symbol.toStringTag
Symbol.toStringTag 和 Symbol.toPrimitive 相似,对象的这个属性的值可以是一个字符串,也可以是一个存取器 get 方法,当在对象上调用 toString 方法时调用这个方法,返回值将作为"[object xxx]"中 xxx 这个值:
let obj = {[Symbol.toStringTag]: "toimc"
};
obj.toString(); // "[object toimc]"
let obj2 = {get [Symbol.toStringTag]() {return "yoyo";}
};
obj2.toString(); // "[object yoyo]"
Symbol.unscopables
这个值和 with 命令有关,但在TS严格模式中,无法使用with。