Iterator 和 for...of 循环

2019-06-10  本文已影响0人  magic_pill

一、Iterator(遍历器)的概念

Iterator 的作用:
Iterator 的遍历过程:
function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}
var it = makeIterator(['a', 'b']);
console.log(it.next())  // { value: "a", done: false }
console.log(it.next())  // { value: "b", done: false }
console.log(it.next())  // { value: undefined, done: true }

说明:定义了一个 makeIterator 遍历器生成函数,它返回一个遍历器对象。对数组执行这个函数,返回数组的遍历器对象 it

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++]} :
        {done: true};
    }
  };
}

注:Iterator 只是把接口规格加到数据结构之上,遍历器与它所遍历的那个数据结构,实际上是分开的;完全可以写出没有对应数据结构的遍历器对象,或者说用遍历器对象模拟出数据结构。

var it = sqrMaker();

console.log(it.next().value) // 0
console.log(it.next().value) // 1
console.log(it.next().value) // 4
console.log(it.next().value) // 9
// ...

function sqrMaker() {
  var index = 0;

  return {
    next: function() {
      return {value: index++ ** 2, done: false};
    }
  };
}

二、默认 Iterator 接口

一个对象如果要具备可被for...of循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法(原型链上的对象具有该方法也可):
  class RangeIterator {
    constructor(start, stop) {
      this.value = start;
      this.stop = stop;
    }

    [Symbol.iterator]() { return this; }

    next() {
      var value = this.value;
      if (value < this.stop) {
        this.value++;
        return {done: false, value: value};
      }
      return {done: true, value: undefined};
    }
  }

  function range(start, stop) {
    return new RangeIterator(start, stop);
  }

  for (var value of range(0, 3)) {
    console.log(value); // 0, 1, 2
  }
为对象添加 Iterator 接口的例子:
    var objt = {
      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 };
            }
          }
        };
      }
    };
    var o = objt[Symbol.iterator]()
    console.log(o.next())   // {value: "hello", done: false}
    console.log(o.next())   // {value: "world", done: false}
    console.log(o.next())   // {value: undefined, done: true}
类数组对象:
类似数组的对象调用数组的 Symbol.iterator 方法的例子:
    let iterable = {
      0: 'a',
      1: 'b',
      2: 'c',
      length: 3,
      [Symbol.iterator]: Array.prototype[Symbol.iterator]
    };
    for (let item of iterable) {
      console.log(item); // 'a', 'b', 'c'
    }

三、调用 Iterator 接口的场景

解构赋值:
扩展运算符:
  // 例一
  var str = 'hello';
  [...str] //  ['h','e','l','l','o']

  // 例二
  let arr = ['b', 'c'];
  ['a', ...arr, 'd']
  // ['a', 'b', 'c', 'd']

补充:只要某个数据结构部署了 Iterator 接口,就可以对它使用扩展运算符,将其转为数组。

yield *

四、字符串的 Iterator 接口

五、Iterator 接口与 Generator 函数

遍历器对象构成条件:

六、for...of 循环

和其它遍历语法的比较:
上一篇 下一篇

猜你喜欢

热点阅读