理解JS中的迭代器和生成器

一、迭代器

在解释什么是迭代器之前先看一下下面的这段代码

var arr = [1,2,3]
for (var i = 0, len - arr.length; i < len; i++){
    console.log(arr[i])
}

这是一个非常常见的for循环,不过它存在一个问题。就是如果嵌套的过多的话,就特别容易出问题,难以维护,还有大量的重复性代码。
就像Promise为了解决回调地域一样,迭代器就是要解决这些嵌套的for循环,让代码更简洁和更容易维护。

特征:迭代器函数定义了一个next()方法,这个方法执行后会返回一个对象,拥有value和done两个属性。为了更好的理解迭代器的运行方式,我们可以自己手写一个迭代器函数,代码如下:

function createIterator (items){
    var i = 0
    return {
        next: function () {
            var done = (i >= items.length)
            var value = !done ? items[i++] : undefined
            return {
                done,
                value
            }
        }
    }
}
var iterator = createIterator([1,2,3])
console.log(iterator.next()) // {value:1, done:false}
console.log(iterator.next()) // {value:2, done:false}

我们定义了一个函数,这个函数每次执行它的next方法的时候都会返回它下次执行的时候的返回值和是否到头了。

二、生成器

如果上面的迭代器理解了,那么我们就来了解一下生成器。
定义:一句话描述生成器就是“一个能够返回一个迭代器函数的函数”。
特征:生成器函数用*function来表示,内部可以使用yield关键字。
现在把上面迭代器的那段代码现在换成生成器的方式来写:

function *createIterator(){
    yield 1
    yield 2
    yield 3
}
let iterator = createIterator()

console.log(iterator.next().value) //1
console.log(iterator.next().value) //2
console.log(iterator.next().value) //3

这样返回的结果和上面的代码一样,不过这些值都是写死的,所以我们改一下,让它能够接受参数。代码如下:

function *createIterator(items){
    for (let i = 0; i< items.length; i++){
        yield items[i]
    }
}
let iterator = createIterator([1,2,3])

console.log(iterator.next()); // { value:1, done: false }
console.log(iterator.next()); // { value:2, done: false }
console.log(iterator.next()); // { value:3, done: false }
console.log(iterator.next()); // { value:undefined, done: true }

好了,看到这里就算是基本理解了,至于一些使用的细节,比如代码格式什么的,去查文档吧。使用场景呢,需要自己去实践中练习。本文追求简单,高效的让你理解什么是迭代器和生成器,所以不能写的太详细和啰嗦,好的文章就是要“干”一点。