1.简介
Symbol(符号)ES6新增数据类型
符号是原始值,并且实例的唯一的、不可变的
符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险,它用来创造唯一记号,用作对象非字符串属性
2. 基础用法
2.1、简单使用
符号需要使用 Symbol() 函数来初始化,使用 typeof 操作符返回的是symbol
使用:let symbol = Symbol() 或者 let symbol = Symbol('description')
唯一性:只要创建符号,并用作对象属性,就一定可以保证,它不会覆盖之前的属性,不管是符号还是字符串
let s1 = Symbol()
let s2 = Symbol()
console.log(s1==s2) // false
let s3 = Symbol('foo')
let s4 = Symbol('foo')
console.log(s3==s4) // false
2.2、共享与重用(使用全局符号注册表)
共享和重用可以使用 Symbol.for() 方法,创建全局注册表
let globalSymbol = Symbol.for('foo') // 第一次创建新得全局符号
let useSymbol = Symbol.for('foo') // 重用
console.log(globalSymbol===useSymbol) // true,在2.1中可以看到,没有使用Symbol.for()方法返回的是false
let localSymbol = Symbol('foo')
console.log(globalSymbol === localSymbol) // false
可以使用 Symbol.keyFor() 方法查询全局注册表
let s = Symbol.for('foo')
console.log(Symbol.keyFor(s)) // foo
2.3、使用符号作为属性
凡是可以使用字符串或者数字作为属性的地方,都可以使用符号
let s1 = Symbol('foo')
let s1 = Symbol('car')
let obj = {
[s1]: 'foo value'
}
obj[s2] = 'car value'
console.log(obj) // {Symbol('foo'): 'foo value', Symbol('car'): 'car value'}
符号属性是对内存中符号的一个引用,直接创建用作属性的符号不会丢失,但是如果没有显式的保存,就要遍历对象的所有属性才能找到相应的属性键
let obj = {Symbol('foo'): 'foo value', Symbol('car'): 'car value'}
// 想要找到Symbol('foo'),必须遍历对象的所有属性
let res = Object.getOwnPropertySymbols(obj).find((f)=> f.toString.match(/foo/))
console.log(res) // Symbol('foo')
3. 内置符号
3.1、Symbol.asyncIterator(表示实现异步迭代器API的函数)
该符号作为一个属性表示:一个方法,该方法返回对象默认的AsyncIterator。由 for-await-of 使用
class Foo {
constructor(name) {
this.name = name;
}
async *[Symbol.asyncIterator]() {
yield new Promise((resolve) => resolve(this.name));
}
}
let f = new Foo("xiaoli");
// 手动调用 next()
let func = f[Symbol.asyncIterator]();
const generator = async () => {
console.log(await func.next()); // {value: "xiaoli", done: false}
console.log(await func.next()); // {value: undefined, done: true}
};
generator();
// 隐式通过异步生成器函数返回
const generator1 = async () => {
for await (const key of f) {
console.log(key); // xiaoli
}
};
generator1();
3.2、Symbol.hasInstance
该符号作为一个属性表示:一个方法,该方法决定一个构造器对象是否认可一个对象是它的实例。由 instanceof 操作符使用。
该属性定义在Function的原型上,所以所有函数和类上都可以调用
function Foo() {}
let f = new Foo()
console.log(Foo[Symbol.hasInstance](f)) // true
class Obj {}
let o = new Obj()
console.log(Obj[Symbol.hasInstance](o)) // true
instanceof 操作符会在原型链上寻找这个属性定义,由于js查找遵循原型链查找,并且采用就近原则,所以我们可以通过定义静态方法重新实现这个函数
class Person {}
class Man extends Person {
static [Symbol.hasInstance]() {
return false
}
}
let p = new Man
console.log(Person[Symbol.hasInstance](p)) // true
console.log(p instanceof Person) // true
console.log(Man[Symbol.hasInstance](p)) // false
console.log(p instanceof Man) // false,这里之所以返回false,是因为在原型链上查找Symbol.hasInstance属性时,在就近的自身中就有这个属性,并且任何时候都返回false,所以这里就使用的自身定义的Symbol.hasInstance
3.3、Symbol.isConcatSpreadable
该符号作为一个属性表示:一个布尔值,如果是true,意味着对象应该调用Array.prototype.concat() 打平其数组元素,fasle 会导致整个对象被追加到数组末尾
let array = [1]
let array1 = [2]
array.concat(array1) // [1,2]
array1[Symbol.isConcatSpreadable] = false
array.concat(array1) // [1,Array(1)]
3.4、Symbol.iterator
该符号作为一个属性表示:一个方法,该方法返回对象默认的迭代器。由 for-of 语句使用。
class Emitter {
constructor(max) {
this.max = max;
this.index = 0;
}
*[Symbol.iterator]() {
while (this.index < this.max) {
yield this.index++;
}
}
}
const func1 = async () => {
let e = new Emitter(5);
for (const x of e) {
console.log(x);
}
};
func1();
3.5、Symbol.match
该符号作为一个属性表示:表示一个正则表达式方法,该方法用正则表达式去匹配字符串。由 String.prototype.match() 使用。
class MyMatch {
constructor(str) {
this.str = str
}
static [Symbol.match](target) {
return target.includes(this.str)
}
}
console.log('abc'.match(new MyMatch('b'))) // true
console.log('abc'.match(new MyMatch('d'))) // false
3.6、Symbol.replace
该符号作为一个属性表示:表示一个正则表达式方法,该方法替换一个字符串中匹配的子串。由 String.prototype.replace() 使用。
Symbol.replace方法接收两个参数,第一个是调用replace方法的字符串实例,第二个是要替换的字符串,实现和match类似
'abcd'.replace(/bc/,'ef') // aefd
3.7、Symbol.search
该符号作为一个属性表示:表示一个正则表达式方法,该方法返回字符串中匹配正则表达式的索引。由 String.prototype.search() 使用。
'abcd'.search(/bc/) // 1
3.8、Symbol.species
3.9、Symbol.split
该符号作为一个属性表示:表示一个正则表达式方法,该方法在匹配正则表达式的索引位置拆分字符串。由 String.prototype.split() 使用。 3.10、Symbol.toPromitive 该符号作为一个属性表示:表示一个方法,该方法将对象转换为相应的原始值 3.11、Symbol.toStringTag 该符号作为一个属性表示:表示一个字符串,该字符串用于创建对象的默认字符串描述 3.12、Symbol.unscopables