Symbol是ECMAScript新增的数据类型,符号是原始值。并且符号实例是唯一,不可变的,进而用作非字符串形式的对象属性,其用途是确保对象属性使用唯一标识符,不会发生属性冲突。
1.符号的基本使用方法
符号需要使用Symbol()函数初始化,因为符号本身是原始类型,所以typeof操作符对符号返回symbol
let syms = Symbol();
console.log(typeof syms); // symbol
在调用函数时,也可以传入字符串参数作为对符号的描述,将来可以通过调用字符串来调用代码,但是这个字符串参数与符号定义或者标识完全无关。
let syms = Symbol();
let othersyms = Symbol();console.log(syms == othersyms); // false;
let sy = Symbol('kkb');
let othersy = Symbol('kkb');
console.log(sy == othersy); // false;
符号没有字面量语法,这也是他们发挥作用的关键,只要创建Symbol()实例并将其用作对象的新属性,就可以保证它不被覆盖已有的对象属性,无论是符号属性还是字符串属性。
let syms = Symbol();
console.log(console.log(syms)); // Symbol();
let KKBsyms = Symbol('kkb');
console.log(console.log(KKBsyms)); // Symbol(kk);
还有一点很重要,Symbol()函数不能与new关键字一起作为构造函数使用,避免创建符号包装对象,像Boolean、String、Number,都支持构造函数且可用于初始化包含原始值得包装对象
let Bool = new Boolean();
console.log(typeof Bool); //'object'
let mySymbol = new Symbol();
console.log(typeof mySymbol); // TypeError :Symbol is not a constructor
如果你确实想使用符号包装对象,可以借助Object()函数;
let symbol = Symbol();
let mySymbol = new Object(symbol);
console.log(typeof mySymbol); // 'object'
2.使用全局符号注册表
使用一个字符串作为键,在全局符号注册表中创建并重用符号,需要用到Symbol.for()方法
let sym = Symbol.for('kkb');
console.log(typeof sym); // symbol
Symbol.for() 对每个字符串键都执行幂等操作,第一次使用某个字符串调用时,他会检查全局运行时注册表,如果不存在就会生成一个新得符号实例并添加进去,后续如果使用会同样操作,如果发现存在,及返回该符号实例。
let sym = Symbol.for('kkb'); //创建新的符号
let othersym = Symbol.for('kkb'); //重用已有符号
console.log(sym === othersym); // true
在举个例子:
采用相同得符号描述,在全局注册表中定义得符号跟使用Symbol()定义得符号也并不等同;
let sym = Symbol('kkb');
let othersym = Symbol.for('kkb');
console.log(sym === othersym); //false
因为,作为参数传给Symbol.for()得任何值都会被转为字符串,注册表中使用得键同时也会被用作符号描述。
let othersym = Symbol.for();
console.log(othersym); // Symbol(undefined);
Symbol.keyFor() 用来查询全局注册表,该方法接收符号,返回该全局符号对应得字符串键,
let sym = Symbol.for('kkb');
console.log(Symbol.keyFor(sym)) //kkb;
如果不是全局符号,返回undefined;
let sym = Symbol('kkb');
console.log(Symbol.keyFor(sym)) //undefined;
如果传得不是符号,则返回TypeError
let sym = Symbol(666);
console.log(Symbol.keyFor(sym)) //TypeError:666 is not symbol;
3.使用符号作为属性
凡是可以使用字符串或者数值作为属性得地方,都可以使用符号,包括了对象字面量属性和Object.defineProperty() / Object.defineProperties()定义得属性,对象字面量只能在计算属性语法中使用符号作为属性。
let sym = Symbol('aaa');
sym2 = Symbol('bbb');
sym3 = Symbol('ccc' ); sym4 = Symbol('ddd' );let alls = { [sym]:'aaa val',
};
也可以这样写
alls[sym]:'aaa val';
console.log(alls); //{Symbol(aaa): "aaa val"}
Object.defineProperty(alls ,sym2, {value:'bbb val'});
console.log(alls); //{Symbol(aaa): "aaa val" , Symbol(bbb): "bbb val"};
Object.defineProperties(alls ,{
[sym3]:{value:'ccc val'},
[sym4]:{value:'ddd val'},});
console.log(alls);
//{
Symbol(aaa): "aaa val" , Symbol(bbb): "bbb val",
Symbol(ccc): "bbb val" ,Symbol(ddd): "ddd val"};
4.常用内置符号
ECMAScript6中也引入了一批常用得内置符号,用于暴露语言内部行为,开发者可以直接访问,重写或模拟这些行为,这些内置符号都是以Symbol工厂函数字符串属性的形式存在。
比如 for-of 循环会在相关对象上使用Symbol.iterator属性,那么就可以通过自定义对象上重新定义Symbol.iterator的值,来改变for-of在迭代该对象时的行为。
他们时全局属性Symbol的普通字符串属性,指向一个符号的实例,所有的内置符号属性都是不可写,不可枚举,不可配置的。
比如经常会引用符号在规范中的名称,前缀为@@。 @@iterator指的就是Symbol.iterator
5.Symbol.asyncIterator 实现异步迭代器API的函数(只有版本比较新的浏览器才支持它)
class KKB{
constructor(max){
this.max=max;
this.asyncIndex=0;
}
async * [Symbol.asyncIterator](){
while(this.asyncIndex<this.max){
yield new Promise((resolve)=>resolve(this.asyncIndex++));
}
}
}
async function asyncNum(){
let kkb = new KKB(5);
for await(const x of kkb){
console.log(x);
}
}
asyncNum();
// 0,1,2,3,4
6. Symbol.hasInstance 表示一个方法,该方法决定一个构造器对象是否认可一个对象是他的实例
function KK(){};
let k = new KK();
console.log(KK[Symbol.hasInstance](k)) //true
class KK{};
let k = new KK();
console.log(KK[Symbol.hasInstance](k)) //true
7. Symbol.isConcatSpreadable 表示一个布尔值,如果是true,则意味着对象应该用Array.prototype.concat()打平其数组元素。
8.Symbol.iterator 表示一个方法,该方法返回对象默认的迭代器。
9.Symbol.match 表示一个正则表达式方法,该方法用正则表达式去匹配字符串。
10.Symbol.replace 表示 一个正则表达式方法,该方法替换一个字符串中匹配的子串。
11.Symbol.search 表示 一个正则表达式方法,该方法返回字符串中匹配正则表达式的索引。
12.Symbol.species 表示一个函数值,该函数作为创建派生对象的构造函数。
13.Symbol.split 表示 一个正则表达式方法,该方法在匹配正则表达式的索引位置拆分字符串。
14.Symbol.toPrimitive 表示一个方法,该方法将对象转换为相应的原始值。
15.Symbol.toStringTag 表示一个字符串,该字符串用于创建对象的默认字符串描述。
16.Symbol.unscopables 表示一个对象,该对象所有的以及继承的属性,都会从关联对象的with环境绑定中排除。