ES6生成器總結

正在進步中。。。發表於2021-01-05

ES6生成器總結

一、生成器的個人理解

首先什麼是生成器:生成器就是Es6中用來設定迭代器的一個函式,我們就可以這樣理解:生成器最終生成的就是迭代器。

生成器:生成器中存在一個iterator介面,也就是說,生成器本身是可以進行迭代的,也就是創造出一個生成器,就相當於建立一個迭代器。關於生成器的用途,對於一些沒有設定迭代器介面的資料型別,我們可以使用生成器來自定義生成一個迭代器,從而進行迭代。
以上便是我對於生成器本身的理解,下面講解具體的語法。

二、生成器的一些屬性
//生成器的宣告
<script>
function* generator(){

  }
let test = generator();
 console.log(test);
</script>
//生成器中的yield關鍵字
<script>
    function* Generator(){
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());

  </script>

最終結果:
在這裡插入圖片描述
解析:由於生成器例項化物件的原型中存在next(),當執行next(),就會根據yield進行迭代。

  <script>
    function* Generator(){
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    console.log(test[Symbol.iterator]);
  </script>
  

在這裡插入圖片描述
又是上面的程式碼可以看出這個生成器存在Symbol.iterator介面,所以可以將其看成一個迭代器

生成器只會在使用初次呼叫函式的時候執行
<script>
    function* Generator(){
      console.log("初次執行函式");
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    console.log(test.next());
  </script>

執行結果是:
在這裡插入圖片描述

在生成器中也會有介面,但是他們預設的迭代器是自引用的,所以下面兩種迭代方式得到相同的結果
<script>
    function* Generator(){
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    // for(const x of test){
    //   console.log(x);
    // }
    for(const x of test[Symbol.iterator]()){
      console.log(x);
    }
  </script>

結果是:在這裡插入圖片描述

生成器物件區分作用域
<script>
    function* Generator() {
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test_1 = Generator();
    let test_2 = Generator();
    console.log(test_1.next());
    console.log(test_2.next());
    console.log(test_1.next());
    console.log(test_2.next());
  </script>

解析:生成器是按照遊標進行輸出的,也就是但是當作用域不同,兩者的遊標互相不影響。
結果:在這裡插入圖片描述

實現yield關鍵字輸出輸入
<script>
    function* Generator() {
      console.log(yield 100);
      console.log(yield 200);
      console.log(yield 300);
      console.log(yield 400);
    }
    let test = Generator();
    console.log(test.next("foo"));
    console.log(test.next("bar"));
    console.log(test.next("btz"));
    console.log(test.next('set'));
    console.log(test.next("map"));
  </script>

結果:在這裡插入圖片描述
這裡當我們傳入第一個的時候,並沒有輸出,這是當我們執行第一個的next()的時候,相當於去開啟執行這個函式,但是這個值並不傳給yield,但是當執行第二個yield的時候,這個yield接收到傳給的值並輸出。

yield*的使用
  <script>
    // function* Generator() {
    //   yield* [1, 2, 3, 4, 5];
    // }
    // let test = Generator();
    // for (const x of test) {
    //   console.log(x);
    // }

    function* Generator(){
      let arr = [1,2,3,4,5];
      for(const x in arr){
        yield arr[x];
      }
    }
    let test = Generator();
    for (const x of test[Symbol.iterator]()){
      console.log(x);
    }
    //1,2,3,4,5
  </script>

以上兩個方法進行迭代,都可以得到相同的結果,yiled*就相當於結構的思想。

yield* 的值最終返回的一定是undefined
  <script>
    function* Generator(){
      console.log(yield* [1,2,3,4,5]);;
    }
    let test = Generator();
    for (const x of test[Symbol.iterator]()){
      console.log(x);
    }
  </script>

最終結果:
在這裡插入圖片描述
其實這裡可以這樣想yield * [1,2,3,4]就等價於 yield 1;yield 2,yield 3;yield 4;由於沒有給yield傳值,所以列印出來的是undefined。

yiled實現遞迴
 <script>
    function* Generator(n) {
      if (n > 0) {
        yield* Generator(n - 1);
        yield n;
      }
    }
    let text = Generator(10);
    for (const x of text) {
      console.log(x);
    }
   //1,2,3,4,5,6,7,8,9,10
  </script>
yiled*後面必須接上一個具有iterator介面的資料型別
<script>
//第一種
    function* gener_1(){
      yield* [1,5,6,3,10];
    }
    function* gener_2(){
      yield* gener_1();
    }
    for(const x of gener_2()){
      console.log(x);
    }
//1,5,6,3,10
  </script>
這裡我們實現手寫三種迭代介面,這三種從上往下更加規範,簡單
<script>
  class Gener {
      constructor() {
        this.value = [1, 2, 3, 4, 5];
      };
      [Symbol.iterator]() {
        let index = 0;
        let value = this.value;
        return {
          next() {
            if (index < value.length) {
              return {
                value: value[index++],
                done: false,
              }
            }
            else {
              return {
                value: undefined,
                done: true
              }
            }
          }
        }
      }
    }
    let test = new Gener();
    for (const x of test) {
      console.log(x);
    }
//第二種
      class Gener{
        constructor() {
          this.value = [1,2,3,4,5];
        }
        *[Symbol.iterator](){
          for(const x of this.value){
            yield x;
          }
        }
      }
      let test = new Gener();
      for (const x of test){
        console.log(x);
      }
  // 第三種
  class Gener{
          constructor(){
            this.value = [1,2,3,4,5];
          }
          *[Symbol.iterator](){
            yield* this.value;
          }
        }
        let test = new Gener();
        for(const x of test){
          console.log(x);
        } 
</script>

這三種最終的結果都是一樣的,為什麼要設定[Symbol.iteerator],是因為class物件中不可以進行迭代。

return方法
<script>
  function * text(){
    yield* [1,2,3,4,5];
  }
  let g = text();
  console.log(g.return("3"));
  </script>

在這裡執行return()的時候,就會返回其中傳入return的值,並且將其done設定為true

關於生成器中的throw()
<script>
    function* text() {
      for (const x of [1, 2, 3]) {
        try {
          yield x;
        }
        catch {
          console.log("這是一個錯誤");
        }
      }
    }
    let test = text();
    console.log(test.next());
    console.log(test.throw("hhhh"));
    console.log(test.next());
    console.log(test.next());
  </script>

解析:這裡一般執行throw()的時候,都會伴隨著try…catch一起使用。當執行這個throw()函式的時候,就相當於傳一個錯誤,所以就不會執行try中的語句,而是執行catch中的語句。然後不會像return()一樣直接退出迭代,throw()會跳過這個進入下一個。
在這裡插入圖片描述
以上便是我對於ES6的生成器的總結,以及自己的理解。總結出來時間已經比較晚了,加油,明天進入物件導向。

相關文章