nonocast/me

ES6 Iterator, generator and yield

Opened this issue · 0 comments

先来复习一下for..in和for..of, 简单来说, for..in在ES5中定义,for..of则是在ES6定义, for..in是遍历对象属性, for..of是遍历对象元素, for..of就用到了Iterator。

let items = ['foo', 'bar'];
for (let item of items) {
  debug(item);
}

从iterator角度来看一下for..of干了什么,

let it = items[Symbol.iterator]();
debug(it.next());       // { value: "foo", done: false }
debug(it.next());       // { value: "bar", done: false }
debug(it.next());       // { value: undefined, done: true }

用while实现如下:

let it = items[Symbol.iterator]();
let item = null;
while (!(item = it.next()).done) {
  debug(item.value);
}

我们可以通过Symbol.iterator来检查对象是否支持iterator,

let isIterable = obj => { return typeof obj[Symbol.iterator] === 'function'; }

isIterable([1, 2, 3]).should.be.true;
isIterable('hello').should.be.true;
isIterable(new Map()).should.be.true;
isIterable(new Set()).should.be.true;
isIterable({}).should.be.false;
isIterable(7).should.be.false;

这里需要值得注意的是,it是不可逆, 一次性的"玩意"。items[Symbol.iterator]是一个创建iterator的function, 可以理解为一个生成器,每次需要时即时生成一个新的iterator, 用完也就丢了, 因为再怎么调用都是返回{ value: undefined, done: true }而已。

由此可见:

  • array作为"provider"在对象上提供了一个方法支持创建iterator
  • 这个创建迭代器的方法称之为generator
  • for..of作为"consumer"使用iterator进行迭代
  • 所以完成for..of就同时需要iterator和generator的配合
  • 而iterator之所以next()每次可以返回不同的值,其中关键就是内部通过yield实现的

现在我们就可以通过generator和yield来亲自DIY下,

function* createIterator() {
  while (true) { yield 1; }
}

let it = createIterator();
it.next().value.should.eq(1);
it.next().value.should.eq(1);
it.next().value.should.eq(1);

May it helps.

参考阅读: