新增的Symbol数据类型来啦

156 阅读5分钟

    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环境绑定中排除。

下期讲点啥呢,讲讲迭代器与生成器吧,大家都来围观呀^~^