迭代器,生成器!!!!!
这是两个一直没太深入研究的东西,终于,今天总算入门了一下!
先说迭代,首先,说到迭代我们第一反应就是数组,因为数组就是最常见的可迭代对象,那么什么又是可迭代对象呢,需满足以下条件:
- 具有迭代器方法;(一般使用[Symbol.iterator]作为属性名)
- 迭代器方法必须放回迭代器对象;
- 迭代器对象必须包含有next方法;
- next方法必须返回包含value属性和done属性的对象。
满足这些条件后,我们迭代可迭代对象诸如数组时,通过调用迭代器方法生成一个迭代器对象,然后一直调用迭代器对象的next方法知道迭代结束,最后done属性返回true。
那为什么要把迭代器跟生成器放在一起总结呢,原因是生成器函数经常被用来作为迭代器的迭代方法(大概是这样?我也不知道,犀牛书说有这个用途~),接下来就来一起看看生成器:
生成器函数通过在普通函数前加上星号*来实现,包含但不限于以下几种形式:
// 函数声明
function* generatorFn(){}
// 对象字面量简写
{
*g(){}
}
生成器函数的内部包含若干代码和yield语句,yield语句后面跟的值就是每次next方法返回的value值(类似return一样提供一个值),ex:
// 1.声明生成器函数
function* generatorFn(){
yield 1;
yield 2;
yield 3;
}
// 2.执行函数,并不会执行函数体内的语句,而是生成一个生成器对象
let gF = generatorFn()
// 3.调用next方法,此时开始从头执行函数体内的语句,直到遇见yield停止,此时返回一个对象,内容为{value:yield语句的值,done:false}
gF.next() // {value:1,done:false}
// 4.继续调用,从上一个yield之后开始,直到下一个yield
gF.next() // {value:2,done:false}
gF.next() // {value:3,done:false}
// 5.全部迭代完毕,此时返回的value为undefined,done为true,表示迭代已完成
gF.next() // {value:undefined,done:true}
看到这里,其实就可以猜到为什么要把生成器跟迭代器一起讲了
我们知道,迭代器方法返回一个迭代器对象,这个对象里应该有next方法,而next方法又需要返回带有value跟done属性的对象
那这里的生成器不是刚好就符合吗,所以我们就完全可以拿生成器函数作为迭代器方法,因此有如下写法:
// 1.定义类
class MyIterableObject {
constructor(){
}
// 2.使用生成器函数作为迭代器方法
*[Symbol.iterator]() {
for(let i=1;i<=3;i++){
yield i
}
}
}
// 3.创建类实例
let mIO = new MyIterableObject
// 4.把迭代器对象保存给变量
let itrt = mIO[Symbol.iterator]()
// 5.依次执行,与上个代码块中同样的效果
console.log(itrt.next()); // {value:1,done:false}
console.log(itrt.next()); // {value:2,done:false}
console.log(itrt.next()); // {value:3,done:false}
console.log(itrt.next()); // {value:undefined,done:true}
ps:补充,当一次次调用next时,一遇到yield语句会立即停止,但在for循环中,for循环体里的语句又都会被执行,不管是在yield前后(如下),这点不知道为什么?留个坑,以后懂了再回来更新。或者有哪位大佬路过刚好看到这,还请赐教一下~
class OddNumberIterable {
constructor(maxNum) {
this.maxNum = maxNum;
this.current = 1;
}
*[Symbol.iterator]() {
for(;this.current<=this.maxNum;this.current+=2) {
console.log(this.current,'before');
yield this.current;
console.log(this.current,'after');
}
}
}
let oddNumbers = new OddNumberIterable(10);
for (let num of oddNumbers) {
console.log(num);
}