多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
- 迭代器 - 什么是迭代器? - 迭代器的作用 - 生成器 - 介绍与应用 - 简单实现 [TOC] ## 迭代器 ### 什么是迭代器? 迭代器(`iterator`)就是一个有`next`方法的对象,每次调用这个对象的next方法都会返回一个**新的对象**,这个新的对象有两个属性,分别是value和done(标识是否已迭代完毕)。 ### 迭代器的作用 在使用`...`语法时,我们能将一个数组展开,像这样 ``` let arr1 = [1,2,3]; let arr2 = [4,5,6]; let arr = [...arr1,arr2]; <<< [1,2,3,4,5,6] ``` 可以发现arr1和arr2都被展开了放在一个数组中。 那么对象能不能像这样展开呢? ``` let obj = {0:1,1:2,2:3,length:3} console.log([...obj]) <<<TypeError: obj is not iterable ``` 我们会发现,它报了一个错误,obj is not iterable,对象是不可迭代的, 嗯。。我们知道数组也是一个对象,但它为什么可以而普通的对象就不行呢? 这就是因为数组对象里有`iterator`,而普通对象里没有,假若我们按照我们之前对迭代器的描述,手动在obj中添加一个 ``` et obj = {0:1,1:2,2:3,length:3,[Symbol.iterator]:function(){ //内部会自动执行下面 每次调用next 通过done来决定是否停止 let index = 0; //当前迭代到了第几个 let self = this; //this指代的是当前对象 return { next:function(){ // value代表的是当前的内容 done代表的是是否迭代完成 return {value:self[index],done:index++ === self.length?true:false} } } }} ``` 我们再试着展开 ``` console.log([...obj]); <<< [1,2,3] ``` 发现确实展开了 这,就是迭代器`iterator`的作用了。 ## 生成器 ### 介绍与应用 生成生成,就是要生点什么,那么`生成器`生了点什么呢?生成器实际上生成了`迭代器`。 嗯,可能这么解释还是不怎么清楚。其实生成器它本身是一个函数,或则说是一个集成的函数,它用`*`来标识它自己,像这样`function *gen(){}`,然后我们每次调用迭代器的next方法的时候,生成器方法就会被执行一部分,只有我们通过不断调用next,这个生成器方法才会被彻底执行完成,并在最后一次next调用时返回done:false的标识。 我们来看一个示例 ``` function *r(){ let content1 = yield read('./1.txt','utf8'); let content2 = yield read(content1,'utf8'); return content2; } let it = r(); ``` 其中`*r`就是一个生成器函数,而`it`就是这个生成器函数生成的迭代器。每一次`it.next()`,生成函数都会执行一部分 ![](https://user-gold-cdn.xitu.io/2018/3/25/1625b30dd5293820?w=397&h=137&f=png&s=27038) 其中青色的线框住的部分就是第一次调用`it.next`时执行的代码,橘色的是第二次,红色的是第三次。 也就是说每次调用时以`yield`为分界的,yield代表产出,它会以yield后面的部分作为`next`调用时返回的value值。 另外还有点需要注意的是生成器里的yield左边的`=`**并不**代表赋值运算,而代表调用`next`时会接受一个参数传入作为输入,**而content1、content2实际上是作为参数传入的形参。** >[warning] **注意:** 第一次迭代是无法传入参数的,但生成器生成迭代器时可以接收参数作为输入。 最后生成器方法的return的值就是最后一次`next`调用时返回的value值,并且此时的done为true。(只有当生成器方法设置了return,才会存中所谓的最后一次next迭代,才会返回true) ### 简单实现 实现原理很简单就是利用闭包 ``` function gen() { let index = 0 , doneValue = false; return function () { if(++index === 3)doneValue=true; if (index === 1) { let V = '1'; return { value: V, done: doneValue } } if (index === 2) { let V = '2'; return { value: V, done: doneValue } } if (index === 3) { let V = '3'; return { value: V, done: doneValue } } } } let it = gen(); let o1 = it(); console.log(o1); let o2 = it(); console.log(o2); let o3 = it(); console.log(o3); <<< { value: '1', done: false } { value: '2', done: false } { value: '3', done: true } ``` 如果我们用babel编译原生的生成器实现的话,会发现内部其实用的是switch,嘛和if差不多。 --- ---未完待续---