唉!你好前端面试!(ㄒoㄒ)Symbol.iterator迭代器的解读

540 阅读3分钟

Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被for……of循环使用

具有如下属性:writable(可写)、enumerable(可迭代)、configurable(可修改,可删除)

  • 当需要对一个对象进行迭代时,它的@@iterator方法都会在不传参的情况下被调用,返回的迭代器用于获取要迭代的值。(一些内置类型拥有默认的迭代器行为,其他类型【如Object】则没有。
  • 自定义迭代器(在具体需求的情况下)

    var myIterable = {}     //Object没有默认的迭代器行为的情况下,创建自定义迭代器
    myIterable[Symbol.iterator] = function *(){     //创建Generator函数实现
        yield 1;
        yield 2;
        yield 3;
    };
    [...myIterable]     //使用展开运算符直接以数组的形式输出==》[1,2,3]
    
  • 迭代协议并非新的内置实现或语法,而是协议。这些协议可被任何遵循某些约定的对象来实现

    迭代协议具体分为两个协议:可迭代协议和迭代器协议

    • 可迭代协议允许JavaScript对象定义或定制它们的迭代行为,例如,在一个for……of结构中,哪些值可以被遍历到。一些内置类型同时是内置可迭代对象StringArrayTypedArrayMapSet】,并且由默认的迭代行为。【需要可迭代对象的语法:for……of循环、展开语法、yield*、解构赋值】

      要成为 可迭代对象,必须实现 **@@iterator**方法。也就意味着对象(或它原型链上的某个对象)必须有一个键为@@iterator的属性,并可通过常量Symbol.iterator访问该属性

    • 迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方法。

      只有实现了一个拥有以下语义的next()方法,一个对象才能成为迭代器

      属性:next 、值(一个无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象:done(boolen)【是否产生序列中的下一个value】 + value【迭代器返回的任何JavaScript值,donetrue时可省略】

      next() 方法必须返回一个对象,该对象应当有两个属性:donevalue

      • String 是一个内置的可迭代对象,默认迭代器会依次返回该字符串的各码点(code point);

        let someString = 'hi';
        console.log(typeof someString[Symbol.iterator]);    //function,具有参数方法【next() 返回两个值:done和value】
        
        let someString = 'hi';
        let iterator = someString[Symbol.iterator](); //调用自身对象方法
        iterator + '';
        console.log(iterator.next()); //每次执行next()方法,输出一个code pint
        console.log(iterator.next());
        console.log(iterator.next());
        
      • 一些内置的语法结构——比如展开语法——其内部实现也使用了同样的迭代协议

        let someString = 'hi';
        console.log([...someString])    //相当于直接调用for……of进行循环输出
        
  • 简单迭代器

    //只有实现了一个拥有以下语义(semantic)的 next() 方法,一个对象才能成为迭代器
    //一个无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象
    //以上两句话的解读如下函数实现
    function makeIterator(array) {
      //自定义一个方法,具备iterator迭代器的结构语法
      let nextIndex = 0;
      return {
        //必须有return
        next: function () {
          return nextIndex < array.length
            ? {
                //三元运算来动态修改done的布尔值
                value: array[nextIndex++], //返回value和done
                done: false,
              }
            : {
                done: true, //改变done的布尔值
              };
        },
      };
    }
    ​
    let it = makeIterator(['哟', '呀']);
    console.log(it.next().value);
    console.log(it.next().value);
    console.log(it.next().value);