迭代器(iterator
)就是一個有next
方法的對象,每次調用這個對象的next方法都會返回一個新的對象,這個新的對象有兩個屬性,分別是value和done(標識是否已迭代完畢)。數組
在使用...
語法時,咱們能將一個數組展開,像這樣bash
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr = [...arr1,arr2];
<<<
[1,2,3,4,5,6]
複製代碼
能夠發現arr1和arr2都被展開了放在一個數組中。babel
那麼對象能不能像這樣展開呢?閉包
let obj = {0:1,1:2,2:3,length:3}
console.log([...obj])
<<<TypeError: obj is not iterable
複製代碼
咱們會發現,它報了一個錯誤,obj is not iterable,對象是不可迭代的,函數
嗯。。咱們知道數組也是一個對象,但它爲何能夠而普通的對象就不行呢?ui
這就是由於數組對象裏有iterator
,而普通對象裏沒有,倘若咱們按照咱們以前對迭代器的描述,手動在obj中添加一個this
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}
}
}
}}
複製代碼
咱們再試着展開spa
console.log([...obj]);
<<<
[1,2,3]
複製代碼
發現確實展開了code
這,就是迭代器iterator
的做用了。cdn
生成生成,就是要生點什麼,那麼生成器
生了點什麼呢?生成器實際上生成了迭代器
。
嗯,可能這麼解釋仍是不怎麼清楚。其實生成器它自己是一個函數,或則說是一個集成的函數,它用*
來標識它本身,像這樣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()
,生成函數都會執行一部分
it.next
時執行的代碼,橘色的是第二次,紅色的是第三次。
也就是說每次調用時以yield
爲分界的,yield表明產出,它會以yield後面的部分做爲next
調用時返回的value值。
另外還有點須要注意的是生成器裏的yield左邊的=
並不表明賦值運算,而表明調用next
時會接受一個參數傳入做爲輸入,而content一、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差很少。
---未完待續---