所有的新概念并不是人们闲的没事想出来的,而是为了解决已有的某些问题才出现的。所以只要我们从历史的角度去看,就能更容易理解这些新概念!
我们在用循环语句迭代数据时,必须要初始化一个变量来记录每次迭代在数据集中的位置,比如说for
循环:
jsconst arr = ['red', 'green', 'blue']
for (let index = 0; index < arr.length; index++) {
console.log(i)
}
在上面的代码中,我们就是通过变量i
来跟踪索引,我们通过观察i
来了解现在循环到数组中的第几个项了。
这个例子中的循环很简单,但是如果嵌套循环,则需要追踪多个变量,代码复杂度增加,就很容易出错。就像Promise
的出现是为了解决回调地域一样,迭代器的出现就是为了消除这种复杂性并减少循环的错误。
为了更好的理解迭代器的运行方式,我们先用 ES5 的语法写一个迭代器函数,代码如下:
jsfunction 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}
console.log(iterator.next()) // {value:3, done:false}
console.log(iterator.next()) // {value:undefined, done:true}
其实这段代码已经给出了迭代器的定义:迭代器函数定义了一个next()
方法,这个方法执行后会返回一个对象,拥有value
和done
两个属性,value
告诉你下次执行时候的返回值,done
告诉你是否执行完了。
生成器就是“能够返回一个迭代器函数的函数”。
上面的迭代器我们是自己定义的,比较麻烦,所以官方出了一个可以生成迭代器的函数,试着比较一下下面两段效果一样的代码:
js// 自定义迭代器
function createIterator(items) {
var i = 0
return {
next: function() {
var done = i >= items.length
var value = !done ? items[i++] : undefined
return {
done,
value
}
}
}
}
// 使用生成器函数返回迭代器
function* createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
就是这么简洁好用!
还是上面那个例子,我们粘过来,不过这一次我们使用生成器函数:
jsfunction* 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 }
其中,function*
用来声明一个生成器,yield
是一个关键字。
yield
是啥?在调用迭代器的next()
方法时,遇到yield
就会暂停,然后返回迭代器的结果对象{ value: xx, done: xx }
。当我们再次调用生成器的next()
方法时,如果它还没执行到头(done 不为 true),那么他就会继续执行。
以上。
本文作者:青波
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!