<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                &emsp;&emsp;根據ES6制訂的標準自定義迭代器實現起來比較復雜,因此ES6又引入了生成器的概念,生成器(Generator)是一個能直接創建并返回迭代器的特殊函數,可將其賦給可迭代對象的Symbol.iterator屬性。與普通函數不同,生成器不僅可以暫停函數內部的執行(即維護內部的狀態),在聲明時還需要包含一個星號(\*),并且擁有next()、return()和throw()三個迭代器方法。 ## 一、function\* &emsp;&emsp;生成器在聲明時,需要把星號加到function關鍵字與函數名之間,但ES6沒有規定星號兩邊是否需要空格,因此下面四種寫法都是允許的,本篇將采用第一種寫法。 ~~~ function* generator() {} function*generator() {} function *generator() {} function * generator() {} ~~~ &emsp;&emsp;生成器也能通過函數表達式創建,如下代碼所示。注意,不能用箭頭函數創建生成器。 ~~~ var iterator = function* () {}; ~~~ &emsp;&emsp;生成器雖然不能作為構造函數使用,但可以是對象的一個方法,并且還支持[第5篇](https://www.cnblogs.com/strick/p/10173583.html)提到的簡潔方式的寫法,如下所示。 ~~~ var obj = { *generator() {} }; ~~~ ## 二、yield &emsp;&emsp;生成器之所以能在其內部實現分批執行,還要多虧ES6新增的yield關鍵字。這個關鍵字可標記暫停位置,具體使用可參考下面的代碼。 ~~~ function* generator() { var count = 0; while (count < 2) yield count++; return count; } var iterator = generator(); ~~~ &emsp;&emsp;雖然生成器的調用方式和普通函數相同,但它不會馬上返回函數的結果(即不能立刻執行)。而是先返回一個它所生成的迭代器,然后再調用其next()方法恢復內部語句的執行(如下代碼所示),直至遇到yield關鍵字,再次暫停,如此反復,一直持續到函數的末尾或碰到return語句才終止這套循環操作。 ~~~ iterator.next(); //{value: 0, done: false} iterator.next(); //{value: 1, done: false} iterator.next(); //{value: 2, done: true} ~~~ **1)yield表達式** &emsp;&emsp;yield關鍵字的后面可以跟一個表達式,例如代碼中的count++。生成器的next()方法能夠返回一個IteratorResult對象,其done屬性用于判斷生成器是否執行完畢,即是否還有yield表達式。關于IteratorResult兩個屬性的值,需要分情況說明,具體如下所列。 &emsp;&emsp;(1)當生成器還在執行時,value的值可通過計算yield表達式得到,done的值為false。 &emsp;&emsp;(2)當生成器執行完畢時,value的值是undefined,done的值為true。 &emsp;&emsp;(3)當遇到return語句時,value的值就是return后面跟的值,done的值為true。 &emsp;&emsp;要想遍歷生成器,除了借助next()方法之外,還可以使用for-of循環。但要注意,遍歷到的是yield表達式的計算結果,如下所示。 ~~~ /******************** 0 1 ********************/ for(var step of iterator) { console.log(step); } ~~~ **2)優先級和結合性** &emsp;&emsp;因為yield可以單獨使用(例如x=yield),所以它并不是一個運算符。雖然如此,但它還是包含優先級和結合性的概念。yield的優先級很低,僅比擴展運算符和逗號高,如果要提前計算,可以像下面這樣用一對圓括號包裹。 ~~~ 1 + (yield 2); ~~~ &emsp;&emsp;yield的結合性與等號一樣,也是從右往左,例如yield yield 1相當于yield(yield 1)。另外,yield有一個很重要的限制,就是它只能存在于生成器內,在其它位置出現都會有異常,包括生成器中的子函數內,如下所示。 ~~~ function* error() { function inner() { yield 1; } } ~~~ ## 三、3個方法 **1)next()** &emsp;&emsp;本節開篇的時候曾提到過生成器包含三個迭代器方法,接下來將圍繞這三個方法展開講解。首先介紹的是next()方法,它能接收一個參數,而這個參數會成為上一個yield表達式的返回值。以下面的代碼為例,calculate()函數包含兩個yield表達式,在創建生成器后,調用了兩次next()方法,第一次沒有傳參,第二次傳入的數字10被賦給了x變量。 ~~~ function* calculate() { let x = yield 1; let y = yield x + 2; return y; } var iterator = calculate(); iterator.next(); //{value: 1, done: false} iterator.next(10); //{value: 12, done: false} ~~~ &emsp;&emsp;注意,第一次調用next()方法時,即使傳進了參數,這個參數也會被忽略,因為此時還不存在上一個yield表達式。 **2)return()** &emsp;&emsp;接下來介紹的是return()方法,它能提前終止當前生成器,類似于在函數體內馬上執行return語句。下面沿用上一個示例,將函數名改成stop,第二次調用的方法改成return()。 ~~~ function* stop() { let x = yield 1; let y = yield x + 2; return y; } var iterator = stop(); iterator.next(); //{value: 1, done: false} iterator.return(10); //{value: 10, done: true} iterator.next(); //{value: undefined, done: true} ~~~ &emsp;&emsp;return()方法也能接收一個參數,而從上面的調用結果中可以得知,這個參數相當于return運算符后面跟的值,如下所示。 ~~~ function* stop() { let x = yield 1; return 10; } ~~~ **3)throw()** &emsp;&emsp;最后介紹的是throw()方法,它能強制生成器拋出一個錯誤。此方法也有一個參數,但這個參數只能被try-catch語句中的catch部分接收。下面用一個例子演示throw()方法的具體使用。 ~~~ function* especial() { var count = 1; try { yield count; } catch (e) { count = 2; console.log(e); //"inner" } yield count + 3; } var iterator = especial(); iterator.next();   //{value: 1, done: false} try { iterator.throw("inner"); //{value: 5, done: false} iterator.next(); //{value: undefined, done: true} iterator.throw("outer"); } catch (e) { console.log(e); //"outer" } ~~~ &emsp;&emsp;在especial生成器的內部和外部各有一條try-catch語句。第一次調用throw()方法,在生成器內部先捕獲拋出的錯誤,再把傳入的字符串“inner”賦給catch的e參數,接著執行yield count + 3,最后返回一個計算過的IteratorResult對象。第二次調用throw()方法,由于生成器已執行完畢,因此只能在外部將錯誤捕獲。 ## 四、yield\* &emsp;&emsp;在yield關鍵字后面跟一個星號(兩邊的空格可選),就能將執行權委托給另一個生成器或可迭代對象。以下面代碼為例,在delegation生成器中,有兩個yield\*表達式,第一個跟的是數組,第二個跟的是generator生成器(相當于將兩個生成器合并)。 ~~~ function* generator() { var count = 0; while (count < 2) yield count++; return count; } function* delegation() { yield* ["a", "b"]; var result = yield* generator(); console.log(result); //2 } var iterator = delegation(); iterator.next(); //{value: "a", done: false} iterator.next(); //{value: "b", done: false} iterator.next(); //{value: 0, done: false} iterator.next(); //{value: 1, done: false} iterator.next(); //{value: undefined, done: true} ~~~ &emsp;&emsp;從上面的遍歷結果中可知,delegation生成器先訪問數組的每個元素,再計算generator生成器中的yield表達式,并將其返回值賦給了result變量。 ## 五、異步編程 &emsp;&emsp;在ES6之前,要實現異步編程,最常用的方法是用回調函數,例如捕獲Ajax通信中的響應內容,如下所示。 ~~~ function fetch(callback) { $.getJSON("server.php", {}, function(json) { callback.call(this, json); }); } function asyn() { fetch(function(json) { console.log(json); //{code: 200, msg: "操作成功"} }); } asyn(); ~~~ &emsp;&emsp;fetch()函數調用了jQuery中能發起Ajax請求的getJSON()方法,在其載入成功時的回調函數內間接調用了callback參數(即傳遞進來的回調函數),其參數就是響應內容。 &emsp;&emsp;接下來將asyn()變為生成器,并在其內部添加yield表達式,然后在getJSON()的回調函數中調用生成器的next()方法,并將響應內容作為參數傳入。 ~~~ function fetch() { $.getJSON("server.php", {}, function(json) { gen.next(json); }); } function* asyn() { var result = yield fetch(); console.log(result); //{code: 200, msg: "操作成功"} } var gen = asyn(); gen.next(); ~~~ &emsp;&emsp;通過上面的代碼可知,生成器能用同步的方式實現異步編程,從而有效避免了層層嵌套的回調金字塔。 ***** > 原文出處: [博客園-ES6躬行記](https://www.cnblogs.com/strick/category/1372951.html) [知乎專欄-ES6躬行記](https://zhuanlan.zhihu.com/pwes6) 已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。 ![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200) 推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
                  <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>

                              哎呀哎呀视频在线观看