JS中的迭代器实现

时间:2018-04-25 18:04:33

标签: javascript node.js ecmascript-6 iterator

我们可以使常规(POJSO)JS对象可迭代,如下所示:

const tempObj = {a: 1, b: 2, c: 3};

tempObj[Symbol.iterator] = function () {
  const self = this;
  const keys = Object.keys(self);
  return {
    next() {
      const k = keys.shift();
      return {
        done: !k,
        value: [k, self[k]]
      }
    }
  }
};

现在我们可以使用for..of循环:

for (let [k,v] of tempObj) {
  console.log(k,v);
}

我们得到:

a 1
b 2
c 3

我的问题是 - 除了next()之外,我们还需要实现另一种方法吗?如果没有,为什么迭代器规范选择返回一个对象而不是只返回一个函数?为什么不是简单的规范:

   tempObj[Symbol.iterator] = function () {
      return function next {
          return {
            done: Object.keys(this).length === 0,
            value: Object.keys(this).shift()
          }
      }
    };

我唯一的猜测是,通过返回一个对象,它为更新/更改留下了空间。

3 个答案:

答案 0 :(得分:2)

Iterator接口还支持另外两种可选方法:returnthrow。来自the ES6 specification,第25.1.1.2节(表54):

  

<强>返回

     

返回IteratorResult对象的函数。归来了   对象必须符合IteratorResult接口。调用此   方法通知Iterator对象调用者不打算   再向Iterator调用下一个方法。归来了   IteratorResult对象通常具有其值的done属性   为true,并且value属性的值作为参数传递   返回方法。但是,此要求未得到强制执行。

     

<强>抛

     

返回IteratorResult对象的函数。返回的对象   必须符合IteratorResult接口。调用此方法   通知Iterator对象调用者已检测到错误   条件。该参数可用于识别错误条件   并且通常是一个异常对象。典型的回应是   抛出作为参数传递的值。如果方法没有抛出,   返回的IteratorResult对象通常具有done属性   它的价值是真的。

ES6规范还说:

  

这些方法的调用者通常应在调用它们之前检查它们是否存在。

所以你绝对不需要实施它们;检查他们存在的负担是在来电者身上。

答案 1 :(得分:2)

  

next()之外还有其他方法需要实现吗?

不,我们需要来实现,但我们可以完整{{3}实施throwreturn }} 即可。例如,生成器对象可以做到这一点。

  

为什么迭代器规范选择返回一个对象而不是只返回一个函数?

因为迭代器(通常)是有状态的,并且从OOP的角度来看,它应该是一个方法而不是(纯)函数。这也允许迭代器实例的原型继承。

答案 2 :(得分:1)

您可以生成Object.entries作为值的生成器。

let tempObj = { a: 1, b: 2, c: 3 };

tempObj[Symbol.iterator] = function* () {
    yield* Object.entries(this);
};

for (let [k, v] of tempObj) {
    console.log(k, v);
}