ES6-Symbol
概述
Symbol
是ES6新引入的原始数据类型,也是JavaScript语言的第七种基本类型
Undefined, Null, Boolean, String, Number, Object, Symbol
引入Symbol
的目的是为了保证每个属性的名字“独一无二”,对象的属性名可以有两种类型:字符串和Symbol
类型
Symbol
值通过Symbol()
生成
1 | let s = Symbol(); |
由于Symbol
值不是对象,故不能在Symbol()
前添加new
1 | let s1 = new Symbol(); |
Symbol
函数可以接受一个字符串作为参数,表示对实例的描述
1 | let s = Symbol('asd'); |
如果Symbol
的参数是一个对象,就会调用该对象的toString
方法,将其转换成字符串,然后再生成一个Symbol
值
1 | const obj = { |
Symbol
函数的参数只表示对当前Symbol
的描述,相同参数的Symbol
函数的返回值不相等
1 | let s1 = Symbol(); |
Symbol
不能与其他类型的值进行运算,但可以显示转换为字符串,也可以转换为布尔值
1 | let s1 = Symbol('asd'); |
作为属性名
每一个Symbol
值都是不相等的,故Symbol
可以作为标志符用于对象的属性名,保证不会出现同名的属性
将Symbol
作为属性名有三种写法
第一种写法:
1
2
3
4
5
6let s = Symbol('asd');
let obj = {};
obj[s] = 'hello';
console.log(obj[s]); // => hello第二种写法:
1
2
3
4
5
6
7let s = Symbol('asd');
let obj = {
[s]: 'hello'
};
console.log(obj[s]); // => hello在对象内部使用
Symbol
定义属性时,Symbol
值必须放在方括号中,原因是命名时会默认将属性名转换成字符串,不会读取作为标志名所指代的值,导致属性名实际上是一个字符串,而不是一个Symbol
值1
2
3
4
5
6
7
8let s = Symbol('asd');
let obj = {
s: 'hello'
};
console.log(obj[s]); // => undefined
console.log(obj['s']); // => hello第三种写法:
1
2
3
4
5
6let s = Symbol('asd');
let obj = {};
Object.defineProperty(obj, s, { value: 'hello' });
console.log(obj[s]); // => hello
Symbol
值作为对象属性名时不能使用点运算符,理由和必须加方括号相同
1 | let s = Symbol('asd'); |
属性名的遍历
Symbol
作为属性名,不会出现在for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
返回
1 | let s = Symbol('asd'); |
可以使用Object.getOwnPropertySymbols()
获取指定对象的所有Symbol
属性名
1 | let s1 = Symbol('s1'), |
也可以使用Reflect.ownKeys
返回所有类型的属性名
1 | let s = Symbol('s'); |
Symbol的内置方法
Symbol.for()
使用给定的key
搜索现有的Symbol
,如果找到则返回该Symbol
;否则将使用给定的key
在全局创建一个新的Symbol
1 | let s1 = Symbol.for('s1'); |
Symbol.keyFor()
从全局注册的Symbol
中,为给定的Symbol
返回对应的key
1 | let s1 = Symbol.for('asd'); |
内置的Symbol值
Symbol.hasInstance
对象的
Symbol.hasInstance
属性指向一个内部方法,对象使用instanceof
运算符时会调用这个方法,判断该对象是否为某个构造函数的实例1
2
3
4
5
6
7
8class Even {
static [Symbol.hasInstance](obj) {
return Number(obj) % 2 === 0;
}
}
1 instanceof Even // => false
2 instanceof Even // => true上述代码中
1 instanceof Even
在语言内部实际调用的是Even[Symbol.hasInstance](1)
Symbol.isConcatSpreadable
对象的
Symbol.isConcatSpreadable
属性是布尔类型,它可以控制数组或类似数组的对象的行为:对于数组对象,默认情况下,用于
Array.prototype.concat
时,会按数组元素展开然后进行连接,重置Symbol.isConcatSpreadable
可以改变默认行为1
2
3
4
5
6
7
8
9let arr1 = [1, 2], arr2 = [3, 4];
arr1[Symbol.isConcatSpreadable] // => undefined
arr2[Symbol.isConcatSpreadable] // => undefined
[1, 2].concat(arr2, 5) // => [1, 2, 3, 4, 5]
arr2[Symbol.isConcatSpreadable] = false;
arr1.concat(arr2, 5) // => [1, 2, [3, 4], 5]对于类似数组的对象,用于
Array.prototype.concat
时,该对象整体作为新数组的元素,重置Symbol.isConcatSpreadable
可改变默认行为1
2
3
4
5
6let obj = { 0: 'a', 1: 'b', length: 2 };
[1, 2].concat(obj, 'c') // => [1, 2, obj, 'c']
obj[Symbol.isConcatSpreadable] = true;
[1, 2].concat(obj, 'c') // => [1, 2, 'a', 'b', 'c']
Symbol.species
Symbol.match
对象的
Symbol.match
属性指向一个函数,当执行str.match(obj)
时,如果该属性存在,会调用它返回该方法的返回值1
2
3String.prototype.match(regexp)
// 相当于
regexp[Symbol.match](this);1
2
3
4
5
6let obj = {
[Symbol.match](str) {
return 'hello'.concat(str);
}
};
'world'.match(obj) // => helloworldSymbol.replace
对象的
Symbol.replace
属性指向一个方法,当对象被String.prototype.replace
方法调用时会返回该方法的返回值1
2
3
4let x = {};
x[Symbol.replace] = (...args) => console.log(args);
'Hello'.replace(x, 'World') // => ['Hello', 'World']Symbol.search
对象的
Symbol.search
属性指向一个方法,当对象被String.prototype.search
方法调用时会返回该方法的返回值1
2
3String.prototype.search(regexp)
// 相当于
regexp[Symbol.search](this)1
2
3
4
5
6
7
8
9
10class MySearch {
constructor(value) {
this.value = value;
}
[Symbol.search](str) {
return console.log(str.indexOf(this.value));
}
}
'asdfgh'.search(new MySearch('df')) // => 2Symbol.split
对象的
Symbol.split
属性指向一个方法,当对象被String.prototype.split
方法调用时会返回该方法的返回值1
2
3String.prototype.split(separator, limit)
// 相当于
separator[Symbol.split](this, limit)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class MySplit {
constructor(value) {
this.value = value;
}
[Symbol.split](str) {
let index = str.indexOf(this.value);
if (index === -1) {
console.log(str);
} else {
console.log([str.substr(0, index), str.substr(index + this.value.length)]);
}
}
}
'asdfgh'.split(new MySplit('asd')); // => ['', 'fgh']
'asdfgh'.split(new MySplit('fgh')); // => ['asd', '']
'asdfgh'.split(new MySplit('qwe')); // => asdfghSymbol.iterator
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables