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。