1. 程式人生 > 其它 >js--生成器總結

js--生成器總結

前言

  生成器gengrator是es6 新增的函式功能,它允許你定義一個包含自有迭代演算法的函式, 同時它可以自動維護自己的狀態。 本文來總結一下JavaScript 中生成器的相關知識點。

正文

  1、 生成器是什麼

  生成器函式提供了一個強大的選擇:它允許你定義一個包含自有迭代演算法的函式, 同時它可以自動維護自己的狀態。 生成器函式使用function*語法編寫。 最初呼叫時,生成器函式不執行任何程式碼,而是返回一種稱為Generator的迭代器。 通過呼叫生成器的下一個方法消耗值時,Generator函式將執行,直到遇到yield關鍵字。

  2、 生成器例項( 通過yield 中斷執行)

  (1)普通生成器函式

  呼叫生成器函式會產生一個類似於迭代器的生成器物件,。生成器物件一開始處於暫停執行(suspended)的狀態。與迭代器相似,生成器物件也實現了 Iterator 介面,它們預設的迭代器是自引用的,因此具有 next() 方法。呼叫這個方法會讓生成器開始執行,遇到yield關鍵字函式暫停,再次呼叫next()繼續執行函式,yield並不回像return 一樣立即結束函式,只是暫停這個生成器函式。

  注意:箭頭函式不能用來定義生成器函式

        function* createIterator() {
            yield 1;
            yield 
2; yield 3; } console.log(createIterator());// createIterator {<suspended>} console.log(createIterator()[Symbol.iterator]());// createIterator {<suspended>},因此可以通過生成器建立迭代器函式 let iterator = createIterator() console.log(iterator.next().value);
//1 console.log(iterator.next().value);//2 console.log(iterator.next().value);//3

  (2)函式表示式的生成器函式,使用函式表示式來建立一個生成器

        let myIterator = function* (items) {
            for (let i = 0; i < items.length; i++) {
                yield items[i]
            }
        }
        let myIterator1 = myIterator([1, 2, 3])
        console.log(myIterator1.next().value);//1
        console.log(myIterator1.next().value);//2
        console.log(myIterator1.next().value);//3

  (3)物件型別的生成器函式

        var obj = {
            createIterator: function* (item) {
                for (let i = 0; i < items.length; i++) {
                    yield items[i]
                }
            }
        }
        // 也可以
        var obj = {
            *createIterator(items) {
                for (let i = 0; i < items.length; i++) {
                    yield items[i]
                }
            }
        }

  生成器會在每個yield 語句後停止執行,在函式中停止執行的能力是極其強大的,yield 關鍵字指定了迭代器在被呼叫next的方法是應當按順序返回的值,在沒有呼叫next() 方法的時候,生成器函式裡的的程式碼並不會執行,同時也可用通過return 返回生成器函式的返回值,如下:

        function* generatorFn() {
            console.log("start")
            yield 'foo';
            yield;
            yield 'bar';
            return 'baz';
        }
        let generatorObject = generatorFn();
        console.log(generatorObject.next()); //start   { done: false, value: 'foo' }
        console.log(generatorObject.next()); // { done: false, value: undefined }
        console.log(generatorObject.next()); // { done: false, value: 'bar' }
        console.log(generatorObject.next()); // { done: true, value: 'baz' }

  3、 yield關鍵字詳解

  (1) yield 關鍵字可以和值或者是表示式在一起使用,因此可以通過生成器給迭代器新增專案,而不是機械化地將專案一個個列出。

        // for迴圈內部使用yield關鍵字
        function* createIterator2(items) {
            //let 塊級作用域
            for (let i = 0; i < items.length; i++) {
                yield items[i]
            }
        }
        let iterator2 = createIterator2([1, 2, 3])
        console.log(iterator2.next());//{value:1,done:false}
        console.log(iterator2.next());//{value:2,done:false}
        console.log(iterator2.next());//{value:3,done:false}
        console.log(iterator2.next());//{value:undefined,done:true}

  注意 :yield 關鍵字只能用於生成器內部,用於其他位置會出現語法錯誤,即使在生成器內部的函式中也不行,下面的程式碼報錯。

        // yield無法穿越函式邊界,在一個巢狀函式中無法將值返回給包含它的函式
        // function* createIterator2(items) {
        //     items.forEach(item => {
        //         yield item +1//語法錯誤
        //     });
        // }

  (2) yield 關鍵字還可以作為函式的中間引數使用

  使用 yield 實現輸入和輸出, yield 關鍵字還可以作為函式的中間引數使用,上一次讓生成器函式暫停的 yield 關鍵字會接收到傳給 next() 方法的第一個值。第一次呼叫 next() 傳入的值不會被使用,因為這一次呼叫是為了開始執行生成器函式

        function* generatorFn(initial) {
            console.log(initial);
            console.log(yield);
            console.log(yield);
        }
        let generatorObject = generatorFn('foo');
        generatorObject.next('bar'); // foo
        generatorObject.next('baz'); // baz
        generatorObject.next('qux'); // qux
        // yield 關鍵字可以同時用於輸入和輸出,如下
        function* generatorFn() {
            return yield 'foo';
        }
        let generatorObject = generatorFn();
        console.log(generatorObject.next()); // { done: false, value: 'foo' }
        console.log(generatorObject.next('bar')); // { done: true, value: 'bar' }

  4、 yield* 委託給其他生成器或者可迭代物件

  (1)yield* 委託給其他可迭代物件

  可以使用星號增強 yield 的行為,讓它能夠迭代一個可迭代物件,從而一次產出一個值,因為 yield * 實際上只是將一個可迭代物件序列化為一連串可以單獨產出的值,所以這跟把 yield放到一個迴圈裡沒什麼不同。下面兩個生成器函式的行為是等價的:

        function* generatorFnA() {
            for (const x of [1, 2, 3]) {
                yield x;
            }
        }
        console.log(generatorFnA());
        for (const x of generatorFnA()) {
            console.log(x);
        }
        // 1
        // 2
        // 3
        function* generatorFnB() {
            yield* [1, 2, 3];
        }
        for (const x of generatorFnB()) {
            console.log(x);
        }
        // 1
        // 2
        // 3

  (2)yield* 委託給其他生成器

        function* createNumberIterator() {
            yield 1;
            yield 2;
            return 3;
        }
        function* createRepeatingIterator(count) {
            for (let i = 0; i < count; i++) {
                yield "repeat";
            }
        }
        function* createCombinedIterator() {
            let result = yield* createNumberIterator();
            yield result;
            yield* createRepeatingIterator(result);
        }

        var iterator = createCombinedIterator();
        console.log(iterator.next()); // "{ value: 1, done: false }"
        console.log(iterator.next()); // "{ value: 2, done: false }"
        console.log(iterator.next()); // "{ value: 3, done: false }"
        console.log(iterator.next()); // "{ value: "repeat", done: false }"
        console.log(iterator.next()); // "{ value: "repeat", done: false }"
        console.log(iterator.next()); // "{ value: "repeat", done: false }"
        console.log(iterator.next()); // "{ value: undefined, done: true }"

  上面的程式碼中createCombinedIterator()生成器委託了 createNumberIterator 生成器,並將它的返回值賦值給了result變數,yeild result 輸入該變數值3,result變數接下來作為引數傳遞 createRepeatingIterator()生成器,提示同一字串需要呼叫3次。

寫在最後

  以上就是本文的全部內容,希望給讀者帶來些許的幫助和進步,方便的話點個關注,小白的成長之路會持續更新一些工作中常見的問題和技術點。