链接:Typescript中文官网,Symbols篇
symbol 是 ES6 新增的一种基本数据类型,它和 number、 string、 boolean、 undefined 和 null 是同类型的,object 是引用类型。它用来表示独一无二的值,通过 Symbol 函数生成。
创建 symbol类型
symbol类型的值是通过Symbol构造函数创建的。
1 2
| const a = Symbol() console.log(typeof a) // symbol
|
Symbol的值是唯一
1 2 3
| let b = Symbol('key') let c = Symbol('key') console.log(b === c) // false
|
用做对象属性的键
1 2 3 4 5
| let d = Symbol() let e = { [d]: 'value' } console.log(e[d]) // value
|
声明对象的属性和类成员
1 2 3 4 5 6 7 8
| const f = Symbol() class G { [f]() { return 'value' } } const h = new G() console.log(h[f]()) // value
|
symbol值可以转为字符串和布尔类型值
1 2 3
| const i = Symbol('i') console.log(i.toString()) // Symbol(i) console.log(Boolean(i)) // true
|
注意:symbol值不可以和其他类型的值进行运算
Symbol属性名的遍历
使用 Symbol 类型值作为属性名,这个属性不会被 for…in 遍历到,也不会被 Object.keys() Object.getOwnPropertyNames() JSON.stringify() 获取到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const name = Symbol('name') const person = { [name]: '老王', age: 30, sex: '男' } let for_key = [] for (let key in person) { for_key.push(key) } console.log(for_key) // [ 'age', 'sex' ] console.log(Object.keys(person)) // [ 'age', 'sex' ] console.log(Object.getOwnPropertyNames(person)) // [ 'age', 'sex' ] console.log(JSON.stringify(person)) // {"age":30,"sex":"男"}
|
使用 Object.getOwnPropertySymbols() 方法获取对象的所有symbol类型的属性名。
1 2 3 4 5 6 7
| const name = Symbol('name') const person = { [name]: '老王', age: 30, sex: '男' } console.log(Object.getOwnPropertySymbols(person)) // [ Symbol(name) ]
|
可以用 ES6 新提供的 Reflect 对象 的静态方法 Reflect.ownKeys,它可以返回所有类型的属性名,所以 Symbol 类型的也会返回。
1 2 3 4 5 6 7
| const name = Symbol('name') const person = { [name]: '老王', age: 30, sex: '男' } console.log(Reflect.ownKeys(person)) // [ 'age', 'sex', Symbol(name) ]
|
众所周知的Symbols
- Symbol.hasInstance
方法,会被instanceof运算符调用。构造器对象用来识别一个对象是否是其实例。
1 2 3 4 5 6 7
| // 当其他对象使用 instanceof 判断是否为这个对象的实例时,会调用你定义的这个方法,参数是其他的这个对象 const obj01 = { [Symbol.hasInstance](other: any) { console.log(other) // { a: 'a' } } } console.log({ a: 'a' } instanceof (obj01 as any)) // false
|
- Symbol.isConcatSpreadable
布尔值,表示当在一个对象上调用Array.prototype.concat时,这个对象的数组元素是否可展开。
1 2 3 4 5 6 7 8
| let arr01 = [1, 2] console.log(arr01.concat([3, 4])) // [ 1, 2, 3, 4 ] let arr02 = ['a', 'b'] as any arr02[Symbol.isConcatSpreadable] = false console.log(arr02.concat(['c', 'd'])) // [ [ 'a', 'b', [Symbol(Symbol.isConcatSpreadable)]: false ], 'c', 'd' ] // 当数组arr02的 Symbol.isConcatSpreadable 设为 true 时,这个数组在数组的 concat 方法中不会被扁平化 arr02[Symbol.isConcatSpreadable] = true console.log(arr02.concat(['e', 'f'])) // [ 'a', 'b', 'e', 'f' ]
|
- Symbol.iterator
方法,被for-of语句调用。返回对象的默认迭代器。
1 2 3 4 5
| const arr = [1, 2] const iterator = arr[Symbol.iterator]() console.log(iterator.next()) // { value: 1, done: false } console.log(iterator.next()) // { value: 2, done: false } console.log(iterator.next()) // { value: undefined, done: true }
|
- Symbol.match
方法,被String.prototype.match调用。正则表达式用来匹配字符串。
1 2 3 4 5 6 7 8 9 10 11 12
| const obj = { [Symbol.match](val: any) { return val.length } } console.log('abcdefg'.match(obj)) // 7
// 正则表达式用来匹配字符串 const str: any = /abcdefg/ str[Symbol.match] = false console.log('/abc/'.startsWith(str)) // false console.log('/abcdefg/'.endsWith(str)) // true
|
- Symbol.replace
方法,被String.prototype.replace调用。正则表达式用来替换字符串中匹配的子串。
1 2 3 4 5 6 7 8 9 10 11
| class obj02 { value: string constructor(value: any) { this.value = value } [Symbol.replace](str: any) { return `${str}:${this.value}` } } const n: any = '姓名' console.log(n.replace(new obj02('老王'))) // 姓名:老王
|
-
Symbol.search
方法,被String.prototype.search调用。正则表达式返回被匹配部分在字符串中的索引。
-
Symbol.species
函数值,为一个构造函数。用来创建派生对象。
-
Symbol.split
方法,被String.prototype.split调用。正则表达式来用分割字符串。
-
Symbol.toPrimitive
方法,被ToPrimitive抽象操作调用。把对象转换为相应的原始值。
-
Symbol.toStringTag
方法,被内置方法Object.prototype.toString调用。返回创建对象时默认的字符串描述。
-
Symbol.unscopables
对象,它自己拥有的属性会被with作用域排除在外。