迭代器(Iterator)ES5实现了迭代器什么是迭代器?当你遇到这个新概念时不要惊慌。迭代器是一个特殊的对象,每个迭代器对象都有一个next(),返回一个对象,包括value和done属性。ES5中实现迭代器的代码如下://实现一个返回迭代器对象的函数。注意这个函数不是迭代器,返回的结果称为迭代器。函数createIterator(items){vari=0;return{next(){vardone=(i>=items.length);//判断i是否小于遍历对象的长度。var值=!完成?项目[i++]:未定义;//如果done为false,则将value设置为当前遍历值。return{done,value}}}}consta=createIterator([1,2,3]);//这个方法最终返回一个对象,包括value和done属性。console.log(a.next());//{value:1,done:false}console.log(a.next());//{value:2,done:false}console.log(a.next());//{value:3,done:false}console.log(a.next());//{value:undefined,done:true}生成器(Generator)生成器是一个函数:used返回一个迭代器。这个概念有两个关键点,一个是函数,一个是迭代器。这个函数不是上面ES5中创建迭代器的函数,而是ES6特有的函数,带*(星号)的函数,还需要用到yield。//生成器函数,ES6内部实现了迭代器函数,你只需要使用yield迭代输出即可。函数*createIterator(){yield1;产量2;yield3;}consta=createIterator();console.log(a.next());//{value:1,done:false}console.log(a.next());//{value:2,done:false}console.log(a.next());//{value:3,done:false}console.log(a.next());//{value:undefined,done:true}生成器的yield关键字有个神奇的作用,就是当你执行一次next()时,只会执行yield之后的内容,然后语句终止。在for循环中使用迭代器即使在for循环中使用yield关键字,它也会暂停循环。function*createIterator(items){for(leti=0;i{yieldvalue//语法错误,在map回调函数中使用yield})}consta=createIterator([1,2,3]);console.log(a.next());//Nooutputgeneratorfunctionexpression函数表达式很简单,就是下面这种写法,也叫匿名函数,不用管它。constcreateIterator=function*(){yield1;yield2;}consta=createIterator();console.log(a.next());给对象添加一个生成器函数一个对象看起来像这样:constobj={}我们可以给obj添加一个生成器,也就是添加一个带星号的方法:constobj={a:1,*createIterator(){yieldthis.a}}consta=obj.createIterator();控制台。日志(a.next());//{value:1,done:false}可迭代对象和forof循环再默读一遍,迭代器是对象,生成器是返回迭代器的函数。生成器生成的所有迭代器都是可迭代对象(可迭代对象具有Symbol.iterator属性),即值可以通过for的迭代。函数*createIterator(){yield1;产量2;yield3;}consta=createIterator();for(letvalueofa){console.log(value)}//123上面的例子告诉我们生成器函数返回的迭代器是一个可迭代对象。其实我们这里要研究的是Symbol.iterator的用法。函数*createIterator(){yield1;产量2;yield3;}consta=createIterator();//a是一个迭代器consts=a[Symbol.iterator]();//使用Symbol.iterator访问迭代器console.log(s.next())//{value:1,done:false}Symbol.iterator也可以用来检测一个对象是否可迭代:typeofobj[Symbol.iterator]==="function"创建可迭代对象在ES6中,arrays,Sets,Maps,strings都是可迭代对象。默认定义的对象是不可迭代的,但可以通过Symbol.iterator创建迭代器。constobj={items:[]}obj.items.push(1);//虽然数组中加入了新的元素,但是obj是不可迭代的for(letxofobj){console.log(x)//_iterator[Symbol.iterator]isnotafunction}//接下来给obj添加生成器,使obj成为可迭代对象。constobj={items:[],*[Symbol.iterator](){for(letitemofthis.items){yielditem;}}}obj.items.push(1)//现在可以通过obj的for进行迭代。for(letxofobj){console.log(x)}内置迭代器上文提到,arrays、Sets、Maps都是可迭代对象,即内部实现了迭代器,提供了三种迭代器函数传递。1.entries()返回一个迭代器:returnkey-valuepairs//arrayconstarr=['a','b','c'];for(letvofarr.entries()){console.log(v)}//[0,'a'][1,'b'][2,'c']//Setconstarr=newSet(['a','b','c']);for(letvofarr.entries()){console.log(v)}//['a','a']['b','b']['c','c']//Mapconstarr=newMap();arr.set('a','a');arr.set('b','b');for(letvofarr.entries()){console.log(v)}//['a','a']['b','b']2、values()返回迭代器:返回键值对的值//数组constarr=['a','b','c'];for(letvofarr.values()){console.log(v)}//'a''b''c'//Setconstarr=newSet(['a','b','c']);for(letvofarr.values()){console.log(v)}//'a''b''c'//Mapconstarr=newMap();arr.set('a','a');arr.set('b','b');for(letvofarr.values()){console.log(v)}//'a''b'3.keys()返回迭代器:返回键//键值对数组constarr=['a','b','c'];for(letvofarr.keys()){console.log(v)}//012//Setconstarr=newSet(['a','b','c']);for(letvofarr.keys()){console.log(v)}//'a''b''c'//Mapconstarr=newMap();到。set('a','a');arr.set('b','b');for(letvofarr.keys()){console.log(v)}//'a''b'虽然上面列出了三种内置的迭代器方法,但不同的集合类型也有自己的默认迭代器。forof中,arrays和Sets的默认迭代器是values(),Maps的默认迭代器是entries()forof循环解构对象本身不支持迭代,但是我们可以加一个generator返回一个key,value迭代器,然后使用forof循环解构键和值。constobj={a:1,b:2,*[Symbol.iterator](){for(letiinobj){yield[i,obj[i]]}}}for(let[key,value]ofobj){console.log(key,value)}//'a'1,'b'2字符串迭代器conststr='abc';for(letvofstr){console.log(v)}//'a''b''c'NodeListiterator迭代器真的无处不在,dom节点的迭代器你应该用过。constdivs=document.getElementByTagName('div');for(letdofdivs){console.log(d)}传播运算符和迭代器consta=[1,2,3];常量b=[4,5,6];constc=[...a,...b]console.log(c)//[1,2,3,4,5,6]高级迭代器功能你说什么?上面说的一堆废话,都是基本功能?有什么高级功能吗?高级功能并不复杂,就是传参、抛异常、生成器返回语句、委托生成器。1.传参生成器中有2个yield。当执行第一个next()时,返回值为1,然后将参数10传递给第二个next(),传入的参数将替换之前的next()产生返回值。在下面的示例中,它是第一个。function*createIterator(){letfirst=yield1;yieldfirst+2;}leti=createIterator();console.log(i.next());//{value:1,done:false}console.log(i.next(10));//{value:12,done:false}2.在迭代器函数中抛出一个错误*createIterator(){letfirst=yield1;yieldfirst+2;}leti=createIterator();console.log(i.next());//{value:1,done:false}console.log(i.throw(newError('error')));//errorconsole.log(i.next());//不再执行3.在生成器return语句生成器中加入return即退出操作。function*createIterator(){letfirst=yield1;返回;yieldfirst+2;}leti=createIterator();console.log(i.next());//{value:1,done:false}console.log(i.next());//{value:undefined,done:true}4.委托生成器生成器嵌套生成器函数*aIterator(){yield1;}function*bIterator(){yield2;}function*cIterator(){yield*aIterator()yield*bIterator()}leti=cIterator();console.log(i.next());//{值:1,完成:假}控制台。日志(i.next());//{value:2,done:false}异步任务执行器在ES6之前,我们使用异步操作的方式是调用函数,执行回调函数。书上举的例子挺好的。在nodejs中,有一个读取文件的操作,使用了回调函数。varfs=require("fs");fs.readFile("xx.json",function(err,contents){//在回调函数中做点什么})那么任务执行器是什么?任务执行器是一个循环执行生成器的函数,因为我们知道生成器需要执行N次next()方法才能跑完,所以我们需要一个自动任务执行器来帮我们做这些事情,也就是任务执行器的作用。下面我们写一个异步任务执行器。//taskDef是生成器函数,run是异步任务执行器函数run(taskDef){lettask=taskDef();//调用生成器letresult=task.next();//执行generator的第一个next(),返回结果functionstep(){if(!result.done){//如果done为false,继续执行next(),循环step直到done为true退出。结果=task.next(result.value);步();}}步();//开始执行step()}测试我们写的run方法,接下来我们不再需要console.logN了,因为run执行器已经帮我们做了循环执行:run(function*(){letvalue=yield1;value=yieldvalue+20;console.log(value)//21})本章总结3个概念,迭代器,生成器,任务执行器。迭代器是一个对象。生成器是最终返回迭代器的函数。任务执行器的一个函数(或者也叫生成器的回调函数),帮助我们自动执行生成器内部的操作,最后返回一个迭代器。不知道大家看到这里,明白三者的区别和用法了吗?=>返回文章列表