JS拾荒の迭代器與生成器

  • 迭代器
    • 什麼是迭代器?
    • 迭代器的做用
  • 生成器
    • 介紹與應用
    • 簡單實現

迭代器

什麼是迭代器?

迭代器(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差很少。


---未完待續---

相關文章
相關標籤/搜索