美文网首页
Symbol 温故知新

Symbol 温故知新

作者: 皮神雷卡丘 | 来源:发表于2019-09-29 15:05 被阅读0次

    Symbol

    1.Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种分别是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object);

    2.Symbol 值通过Symbol函数生成,可以作为对象的属性名使用,保证不会与其他属性名产生冲突;

    let s = Symbol();
    typeof s  // symbol
    

    ps:上面代码表示创建一个Symbol变量,值得注意的是,Symbol函数前不能使用new命令,否则会报错,也就是说Symbol 是一个原始类型的值,不是对象,也不能添加属性;

    3.Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要用于区分不同的 Symbol 变量;

    let s1 = Symbol('a');
    let s2 = Symbol('b');
    
    s1.toString()  // 'Symbol(a)'
    s2.toString()  // 'Symbol(b)'
    

    ps:Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的

    let s1 = Symbol('a');
    let s2 = Symbol('a');
    
    s1 === s2  //false
    

    4.Symbol 值不能与其他类型的值进行运算,但可以转为布尔值,但是不能转为数值;

      let s = Symbol();
      s + '2'       // Cannot convert a Symbol value to a string
      Boolean(s)    // true
      !s            // false
    

    5.用于对象的属性名,可以保证不会出现同名的属性,对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖;值得注意的是,Symbol 值作为对象属性名时,不能用点运算符,因为点运算符后面是一个字符串;

    let s = Symbol();
    
    let obj = {};
    obj[s] = 'hello world';
    
    //或者
    
    let obj  = {
        [s] : 'hello world'
    }
    
    obj.s   // undefined
    obj[s]  // hello world
    

    6.Symbol 作为属性名,不会被常规方法遍历得到,即该属性不会出现在for...infor...of循环中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回,但是,它并不是私有属性,可以使用 Object.getOwnPropertySymbols 方法,可以获取指定对象的所有 Symbol 属性名;

    var obj = {};
    var a = Symbol('a');
    var b = Symbol('b');
    
    obj[a] = 'Hello';
    obj[b] = 'World';
    obj.c  = 'Mine';
    
    for( let key in obj ){
       console.log(key)         // c
    }
    
    var objectSymbols = Object.getOwnPropertySymbols(obj);
    
    console.log(objectSymbols) // [Symbol(a), Symbol(b)]
    

    7.Symbol.for方法接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值;它与Symbol()不同的是,Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值,而 Symbol()每次都会返回3不同的Symbol值;

    Symbol.for("name") === Symbol.for("name")
    // true
    
    Symbol("name") === Symbol("name")
    // false
    

    8.Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key,而Symbol()写法是没有登记机制的;

    var s1 = Symbol.for("name");
    Symbol.keyFor(s1) // "name"
    
    var s2 = Symbol("name");
    Symbol.keyFor(s2) // undefined
    

    ps:Symbol.for为Symbol值登记的名字,是全局环境的,可以在不同的 iframeservice worker 中取到同一个值
    9.Symbol.iteratores6中有三类结构生来就具有Iterator接口:数组、类数组对象、MapSet结构。

      const obj = {
        data: ['hello', 'world'],
        [Symbol.iterator]() {
          const self = this;
          let index = 0;
          return {
            next() {
              if (index < self.data.length) {
                return {
                  value: self.data[index++],
                  done: false
                };
              } else {
                return { value: undefined, done: true };
              }
            }
          };
        }
      }
      // const arr = ['hello2', 'world2'];
      // @ts-ignore
      for (const iterator of obj) {
        console.log(obj)
        console.log(iterator)
      }
    

    至于对象没有布置iterator接口的原因,数组,Map等结构中的成员都是有顺序的,即都是线性的结构,而对象,各成员并没有一个确定的顺序,所以遍历时先遍历谁后遍历谁并不确定。所以,给一个对象部署iterator接口,其实就是对该对象做一种线性转换。如果你有这种需要,就需要手动给你的对象部署iterator接口!
    可以看到,Symbol.iterator会返回一个对象,这就是一个遍历器对象,而作为遍历器对象,其必须具备的特征就是必须具备next()方法。至于可以使用Array.from转换成数组的类数组对象,部署iterator有一种很简单的方法,即直接使用数组的[Symbol.iterator]接口

    fakeArray.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
    
        const objIterator = {
          data: ['111', '222'],
          [Symbol.iterator] : function* () {
            const self = this;
            for (const data of self.data) {
              yield data;
            }
          }
        }
        // const arr = ['hello2', 'world2'];
        // @ts-ignore
        for (const iterator of objIterator) {
          console.log(obj)
          console.log(iterator)
        }
    
    image.png
    所以Array,Set,Map原型链上的[Symbol.iterator]实现的实质也是用的yield.
    掘金上大神讲解的迭代器和生成器
    但是Array.prototype[Symbol.iterator]Array.prototype.entries 会返回同一个迭代器是错误的说法
    entries()返回的迭代器执行的next()方法是一个首元素为当前迭代idx的数组!
    Array.prototype.entries.png
    *async/await

    async函数就是generator函数的语法糖。
    async函数,就是将generator函数的*换成async,将yield替换成await。
    【async函数对generator的改进】
    (1)内置执行器,不需要使用next()手动执行。
    (2)await命令后面可以是Promise对象或原始类型的值,yield命令后面只能是Thunk函数或Promise对象。
    (3)返回值是Promise。返回非Promise时,async函数会把它包装成Promise返回。(Promise.resolve(value))

    相关文章

      网友评论

          本文标题:Symbol 温故知新

          本文链接:https://www.haomeiwen.com/subject/lwjjuctx.html