<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # generator generator(生成器)是ES6標準引入的新的數據類型。一個generator看上去像一個函數,但可以返回多次。 ES6定義generator標準的哥們借鑒了Python的generator的概念和語法,如果你對Python的generator很熟悉,那么ES6的generator就是小菜一碟了。如果你對Python還不熟,趕快惡補[Python教程](http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317799226173f45ce40636141b6abc8424e12b5fb27000)!。 我們先復習函數的概念。一個函數是一段完整的代碼,調用一個函數就是傳入參數,然后返回結果: ``` function foo(x) { return x + x; } var r = foo(1); // 調用foo函數 ``` 函數在執行過程中,如果沒有遇到`return`語句(函數末尾如果沒有`return`,就是隱含的`return undefined;`),控制權無法交回被調用的代碼。 generator跟函數很像,定義如下: ``` function* foo(x) { yield x + 1; yield x + 2; return x + 3; } ``` generator和函數不同的是,generator由`function*`定義(注意多出的`*`號),并且,除了`return`語句,還可以用`yield`返回多次。 大多數同學立刻就暈了,generator就是能夠返回多次的“函數”?返回多次有啥用? 還是舉個栗子吧。 我們以一個著名的斐波那契數列為例,它由`0`,`1`開頭: ``` 0 1 1 2 3 5 8 13 21 34 ... ``` 要編寫一個產生斐波那契數列的函數,可以這么寫: ``` function fib(max) { var t, a = 0, b = 1, arr = [0, 1]; while (arr.length < max) { t = a + b; a = b; b = t; arr.push(t); } return arr; } // 測試: fib(5); // [0, 1, 1, 2, 3] fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] ``` 函數只能返回一次,所以必須返回一個`Array`。但是,如果換成generator,就可以一次返回一個數,不斷返回多次。用generator改寫如下: ``` function* fib(max) { var t, a = 0, b = 1, n = 1; while (n < max) { yield a; t = a + b; a = b; b = t; n ++; } return a; } ``` 直接調用試試: ``` fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window} ``` 直接調用一個generator和調用函數不一樣,`fib(5)`僅僅是創建了一個generator對象,還沒有去執行它。 調用generator對象有兩個方法,一是不斷地調用generator對象的`next()`方法: ``` var f = fib(5); f.next(); // {value: 0, done: false} f.next(); // {value: 1, done: false} f.next(); // {value: 1, done: false} f.next(); // {value: 2, done: false} f.next(); // {value: 3, done: true} ``` `next()`方法會執行generator的代碼,然后,每次遇到`yield x;`就返回一個對象`{value: x, done: true/false}`,然后“暫停”。返回的`value`就是`yield`的返回值,`done`表示這個generator是否已經執行結束了。如果`done`為`true`,則`value`就是`return`的返回值。 當執行到`done`為`true`時,這個generator對象就已經全部執行完畢,不要再繼續調用`next()`了。 第二個方法是直接用`for ... of`循環迭代generator對象,這種方式不需要我們自己判斷`done`: ``` for (var x of fib(5)) { console.log(x); // 依次輸出0, 1, 1, 2, 3 } ``` generator和普通函數相比,有什么用? 因為generator可以在執行過程中多次返回,所以它看上去就像一個可以記住執行狀態的函數,利用這一點,寫一個generator就可以實現需要用面向對象才能實現的功能。例如,用一個對象來保存狀態,得這么寫: ``` var fib = { a: 0, b: 1, n: 0, max: 5, next: function () { var r = this.a, t = this.a + this.b; this.a = this.b; this.b = t; if (this.n < this.max) { this.n ++; return r; } else { return undefined; } } }; ``` 用對象的屬性來保存狀態,相當繁瑣。 generator還有另一個巨大的好處,就是把異步回調代碼變成“同步”代碼。這個好處要等到后面學了AJAX以后才能體會到。 沒有generator之前的黑暗時代,用AJAX時需要這么寫代碼: ``` ajax('http://url-1', data1, function (err, result) { if (err) { return handle(err); } ajax('http://url-2', data2, function (err, result) { if (err) { return handle(err); } ajax('http://url-3', data3, function (err, result) { if (err) { return handle(err); } return success(result); }); }); }); ``` 回調越多,代碼越難看。 有了generator的美好時代,用AJAX時可以這么寫: ``` try { r1 = yield ajax('http://url-1', data1); r2 = yield ajax('http://url-2', data2); r3 = yield ajax('http://url-3', data3); success(r3); } catch (err) { handle(err); } ``` 看上去是同步的代碼,實際執行是異步的。 ## 練習 要生成一個自增的ID,可以編寫一個`next_id()`函數: ``` var current_id = 0; function next_id() { current_id ++; return current_id; } ``` 由于函數無法保存狀態,故需要一個全局變量`current_id`來保存數字。 不用閉包,試用generator改寫: ``` 'use strict'; function* next_id() { } // 測試: var x, pass = true, g = next_id(); for (x = 1; x < 100; x ++) { if (g.next().value !== x) { pass = false; alert('測試失敗!'); break; } } if (pass) { alert('測試通過!'); } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看