当前位置: 首页 > Web前端 > CSS

ES6中Iterator和Generator

时间:2023-03-31 02:00:10 CSS

Iterator的作用是为各种数据结构提供统一方便的访问接口;(统一),其次使数据结构的成员能够按一定顺序排列;(按顺序)三是ES6新增了for...of循环的遍历命令,Iterator接口主要用于for...of的消费。例如:遍历器生成函数返回一个遍历器对象,next方法返回一个表示当前数据成员信息的对象。这个对象有两个属性,value和done。value属性返回当前位置的成员。done属性是一个布尔值,表示遍历是否结束。函数makeIterator(数组){varnextIndex=0;return{next:function(){returnnextIndex',value);}//第三种方式:function*objectEntries(obj){letpropKeys=Reflect.ownKeys(obj);for(letpropKeyofpropKeys){yield[propKey,obj[propKey]];}}for(let[key,value]ofobjectEntries(obj)){console.log(`${key}:${value}`);}//也可以这样letjane={first:'Jane',last:'Doe'};jane[Symbol.iterator]=objectEntries;//这句是给上面的对象Symbol.iterator属性添加Generator函数for(let[key,value]ofjane){console.log(`${key}:${value}`);}Generator简介在我看来,Generator就是提供一种异步编程的解决方案;Generator函数是一个普通函数。其实就是一个遍历器生成函数,但是有几个特点:1.函数关键字和函数名之间有一个星号(星号紧跟在函数关键字后面);2.在函数体内使用yield表达式来定义不同的内部状态(yield在英文中表示“输出”1)yield只能在Generator函数中使用;2)如果yield表达式用在另一个表达式中,必须放在括号中;3)yield表达式作为函数参数或者放在赋值表达式的右边,不带括号);3.Generator函数可以理解为状态机。调用Generator函数后,函数并没有执行,返回的不是函数的结果,而是一个指向内部状态的指针对象。每次调用next方法时,内部指针都会从函数头或上次停止的地方开始执行,直到遇到下一个yield表达式(或return语句)为止;Generator函数是分段执行的,yield表达式是暂停执行的标记,next方法可以恢复执行varmyIterable={};myIterable[Symbol.iterator]=function*(){yield1;产量2;yield3;};[...myIterable]Generator函数执行后,返回一个遍历器对象。对象本身也有一个Symbol.iterator属性,执行后会返回自己。function*gen(){//somecode}varg=gen();g[Symbol.iterator]()===gGenerator中next方法的参数传递next方法的参数,后面有一种方式Generator函数开始运行,并继续向函数体中注入值。由于next方法的参数代表了前面yield表达式的返回值,所以next方法第一次不能带参数使用。V8引擎在第一次使用next方法时直接忽略参数,从第二次使用next方法开始参数才有效。让我们举一个简单的例子:function*dataConsumer(){console.log('Started');console.log(`1.${yield}`);console.log(`2.${yield}`);return'result';}letgenObj=dataConsumer();genObj.next();//StartedgenObj.next('a')//1.ageObj.next('b')//2.b有点多复杂:函数*foo(x){vary=2*(yield(x+1));varz=yield(y/3);返回(x+y+z);}vara=foo(5);a.next()//Object{value:6,done:false}a.next()//Object{value:NaN,done:false}a.next()//Object{value:NaN,done:true}varb=foo(5);b.next()//{value:6,done:false}b.next(12)//{value:8,done:false}//解释结果y=2*12所以返回的是24/3b.next(13)//{value:42,done:true}//y=24z=13所以返回的是5+24+13下面说说for的关系的和发电机。需要注意的是,当next方法返回done为true时,循环终止,不包含return对象,所以上面代码的return语句返回的6不包含在for...of循环中函数*foo(){产量1;产量2;产量3;产量4;产量5;return6;}for(letvoffoo()){console.log(v);}Generator中的throw方法Generator函数返回的遍历器对象有一个throww方法可以在函数体外部抛出一个错误,然后在Generator函数体中捕获它。throw方法可以接受一个参数,该参数将由catch语句接收varg=function*(){try{yield;}catch(e){console.log(e);}};vari=g();i.next();i.throw(newError('Error!'));//错误:错误!(...)throw方法被捕获后,会顺带执行下一个yield表达式,即顺带执行next方法。vargen=function*gen(){try{yieldconsole.log('a');}catch(e){//...}yieldconsole.log('b');yieldconsole.log('c');}varg=gen();g.next()//ag.throw()//bg.next()//在cGenerator中throw有什么好处?多个yield表达式,只用一个try...catch代码块就可以捕获错误,大大方便了错误的处理。一旦在Generator执行期间抛出错误并且没有被内部捕获,它将不会被执行任何进一步的function*g(){yield1;console.log('抛出异常');thrownewError('发电机坏了!');产量2;yield3;}上图代码:因为抛出异常generatorbroke,所以后面2和3不会返回Generatorreturnfunction*gen(){yield1;产量2;yield3;}varg=gen();g.next()//{value:1,done:false}g.return('foo')//{value:"foo",done:true}g.next()//{value:undefined,done:true}g调用return方法后,返回值的value属性为return方法的参数foo。并且,Generator函数的遍历终止,返回值的done属性为true,后面调用next方法,done属性始终返回true另一种特殊情况:里面有一个try...finally代码块Generator函数,然后return方法将被推迟到执行完finally代码块。也就是说:调用return方法后,执行finally代码块,执行finally代码块后,再执行return方法。函数*数字(){产量1;尝试{产量2;产量3;}最后{产量4;产量5;}yield6;}varg=numbers();g.next()//{value:1,done:false}g.next()//{value:2,done:false}g.return(7)//{value:4,done:false}g.next()//{value:5,done:false}g.next()//{value:7,done:true}yield*表达式公式yield表达式后面跟着一个遍历器对象,yield表达式后面需要加一个星号,表示它返回的是一个遍历器对象。