一文大白话讲清楚ES6迭代器Iterator和生成器Generator的原理和作用
1. 是啥迭代器Iterator
迭代迭代,就是一个接着一个,怎么一个接着一个呢,就是next(),在next() 迭代器是一种特殊的对象,每个迭代器都有一个next()方法,每次调用next方法都会返回一个结果对象,结果对象有两个属性,一个是value,一个是done。value表示本次next()所取到的值,而done是布尔值,表示是不是已经取完所有值 迭代器内部有一个指向集合中值的位置额指针,每次next()以后,该指正移动到下一个值得位置 所以我们很容易设计一个迭代器 上代码
function createIterator ( items ) {
let i= 0 ;
return {
next : function ( ) {
let done= ( i>= items. length)
let value= ! done? items[ i++ ] : undefined ;
return {
done,
value
}
}
}
}
let iterator= createIterator ( [ 1 , 2 , 3 , 4 , 5 ] )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
2. 啥是生成器Generator
2.1 生成器的理解
上面讲了迭代器,生成器是啥,生成器就是生成迭代器的方法 说白了,就是用生成器生成迭代器 怎么生成了,两个关键*标明方法名为迭代器,然后用yield语句进行迭代 上代码
function * generator ( items ) {
for ( var i = 0 ; i < items. length; i++ ) {
yield items[ i]
}
}
let iterator= generator ( [ 1 , 2 , 3 , 4 , 5 ] )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
当然,generator本身是个普通函数,他可以有返回值
function * generator ( items ) {
let num= 0 ;
for ( var i = 0 ; i < items. length; i++ ) {
num++
yield items[ i]
}
if ( num>= items. length) {
return 'over'
}
}
let iterator= generator ( [ 1 , 2 , 3 , 4 , 5 ] )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( ) )
发现没有,如果有返回值,最后一项的value是返回值,而不是undefined的了 所以,generator的整体运行逻辑是这样的
被调用生成迭代器本身 调用next()方法开始执行 执行遇到yeild,就暂停后面的操作,并把紧跟在yield后面的表达式的值作为返回对象的value属性值,done值为true 再次调用next()方法,再继续往下执行,直到遇到新的yield, 重复执行,直到碰到return或者执行完;如果碰到return,则罢return的值作为返回对象value的属性值,done为false。如果没有碰到return,就把undefined作为返回对象value的属性值,done为false。表示迭代完成
2.2 next传参
next既然是一个方法,那我们就可以向next()方法传入参数,传入的参数会被当成上一个yield的返回值‘
function * calculate ( num ) {
let x= 3 * ( yield ( num+ 2 ) )
let y= yield ( x/ 4 )
return ( num+ x+ y)
}
let iterator= calculate ( 10 )
console. log ( iterator. next ( ) )
console. log ( iterator. next ( 16 ) )
console. log ( iterator. next ( 3 ) )
调用calculate(10)生成迭代器,这时候迭代器里面的num=10 执行next,碰到yield(num+2),停下来,返回num+2,也就是12//12 执行next(12),传入的参数相当于上一次yield的返回值,也就是说,此时yield(num+2)=16,所以x=3816=48;执行到yield (x/4)时,听,返回x/4=12//12 执行next(3),同理,相当于yield (x/4)=3,也就是y=3,执行到return,结束,返回num+x+y=10+48+3=61//61 结束
2.3 for…of遍历
因为generator返回Iterator对象,所以我们可以使用for…of进行遍历
function * generator ( items ) {
for ( var i = 0 ; i < items. length; i++ ) {
yield items[ i]
}
}
let iterator= generator ( [ 1 , 2 , 3 , 4 , 5 ] )
for ( var x of iterator) {
console. log ( x)
}
我们也可以对原生对象加上generator,是的他可以通过for…of进行遍历
function * objGenerator ( obj ) {
let propKeys= Reflect. ownKeys ( obj)
for ( var x of propKeys) {
yield [ x, obj[ x] ]
}
}
let obj= {
name : 'tom' ,
age : 12 ,
hight : 153
}
let objIterator= objGenerator ( obj)
for ( var [ key, value] of objIterator) {
console. log ( key, value)
}
3.generator异步处理
function * generator ( ) {
const f1 = yield readFile ( 'variable.js' ) ;
const f2 = yield readFile ( 'index.html' ) ;
} ;
let g= generator ( )
g. next ( )
g. next ( )
4. generator的语法糖,更便捷的async和await
async和await其实就是generator的语法糖,更为简洁,语义化更强
async function generator ( ) {
const f1 = await readFile ( 'variable.js' ) ;
const f2 = await readFile ( 'index.html' ) ;
} ;
let g= generator ( )