久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      解析JavaScript中的Generators

      最近,為了更好地理解Redux Sagas的工作原理,我重學(xué)了JavaScript generators的知識(shí),我把從網(wǎng)上收集到的各種知識(shí)點(diǎn)濃縮到一篇文章里,我希望這篇文章既通俗易懂,又足夠嚴(yán)謹(jǐn),可以作為初學(xué)者的generators使用指南。

      簡(jiǎn)介

      JavaScript在ES6時(shí)引入了生成器。生成器函數(shù)與常規(guī)函數(shù)類似,除了可以暫停和恢復(fù)它們這一點(diǎn)以外。生成器也與迭代器密切相關(guān),因?yàn)樯善鲗?duì)象就是迭代器。
      在JavaScript中,函數(shù)調(diào)用后通常不能暫?;蛲V埂?是的,異步函數(shù)在等待await語(yǔ)句時(shí)暫停,但是異步函數(shù)在ES7時(shí)才引入。此外,異步函數(shù)是建立在生成器之上的。)一個(gè)普通函數(shù)只有在返回或拋出錯(cuò)誤時(shí)才會(huì)結(jié)束。

      function foo() {   console.log('Starting');   const x = 42;   console.log(x);     console.log('Stop me if you can');     console.log('But you cannot');  }

      相反,生成器允許我們?cè)谌我鈹帱c(diǎn)處暫停執(zhí)行,并從同一斷點(diǎn)恢復(fù)執(zhí)行。

      生成器和迭代器

      來(lái)自MDN:

      在JavaScript中,迭代器是一個(gè)對(duì)象,它定義一個(gè)序列,并在終止時(shí)可能返回一個(gè)返回值。 >更具體地說(shuō),迭代器是通過(guò)使用 next() 方法實(shí)現(xiàn) Iterator protocol >的任何一個(gè)對(duì)象,該方法返回具有兩個(gè)屬性的對(duì)象: value,這是序列中的 next 值;和 done, 如果已經(jīng)迭代到序列中的最后一個(gè)值,則它為 true 。如果 value 和 done 一起存在,則它是迭代器的返回值。

      因此,迭代器的本質(zhì)就是:

      • 定義序列的對(duì)象
      • 有一個(gè)next()方法…
      • 返回一個(gè)具有兩個(gè)屬性的對(duì)象:value和done

      是否需要生成器來(lái)創(chuàng)建迭代器?不。事實(shí)上,我們已經(jīng)可以使用閉包pre-ES6創(chuàng)建一個(gè)無(wú)限的斐波那契數(shù)列,如下例所示:

      var fibonacci = {   next: (function () {     var pre = 0, cur = 1;     return function () {       tmp = pre;       pre = cur;       cur += tmp;       return cur;     };   })() };  fibonacci.next(); // 1 fibonacci.next(); // 2 fibonacci.next(); // 3 fibonacci.next(); // 5 fibonacci.next(); // 8

      關(guān)于生成器的好處,我將再次引用MDN:

      雖然自定義迭代器是一個(gè)有用的工具,但是由于需要顯式地維護(hù)它們的內(nèi)部狀態(tài),創(chuàng)建它們需要我們仔細(xì)地編程。生成器函數(shù)提供了一個(gè)強(qiáng)大的替代方法:它們?cè)试S我們通過(guò)編寫(xiě)一個(gè)執(zhí)行不是連續(xù)的函數(shù)來(lái)定義迭代算法。
      換句話說(shuō),使用生成器創(chuàng)建迭代器更簡(jiǎn)單(不需要閉包!),這意味著出錯(cuò)的可能性更小。
      生成器和迭代器之間的關(guān)系就是生成器函數(shù)返回的生成器對(duì)象是迭代器。

      語(yǔ)法

      生成器函數(shù)使用function *語(yǔ)法創(chuàng)建,并使用yield關(guān)鍵字暫停。
      最初調(diào)用生成器函數(shù)并不執(zhí)行它的任何代碼;相反,它返回一個(gè)生成器對(duì)象。該值通過(guò)調(diào)用生成器的next()方法來(lái)使用,該方法執(zhí)行代碼,直到遇到y(tǒng)ield關(guān)鍵字,然后暫停,直到再次調(diào)用next()。

      function * makeGen() {   yield 'Hello';   yield 'World'; }  const g = makeGen(); // g is a generator g.next(); // { value: 'Hello', done: false } g.next(); // { value: 'World', done: false } g.next(); // { value: undefined, done: true }

      在上面的最后一個(gè)語(yǔ)句之后重復(fù)調(diào)用g.next()只會(huì)返回(或者更準(zhǔn)確地說(shuō),產(chǎn)生)相同的返回對(duì)象:{ value: undefined, done: true }。

      yield暫停執(zhí)行

      大家可能會(huì)注意到上面的代碼片段有一些特殊之處。第二個(gè)next()調(diào)用生成一個(gè)對(duì)象,該對(duì)象的屬性為done: false,而不是done: true。
      既然我們正在生成器函數(shù)中執(zhí)行最后一條語(yǔ)句,那么done屬性不應(yīng)該為true嗎?并不是的。當(dāng)遇到y(tǒng)ield語(yǔ)句時(shí),它后面的值(在本例中是“World”)被生成,執(zhí)行暫停。因此,第二個(gè)next()調(diào)用暫停在第二個(gè)yield語(yǔ)句上,因此執(zhí)行還沒(méi)有完成—只有在第二個(gè)yield語(yǔ)句之后執(zhí)行重新開(kāi)始時(shí),執(zhí)行才算完成(即done: true),并且不再運(yùn)行代碼。
      我們可以將next()調(diào)用看作是告訴程序運(yùn)行到下一個(gè)yield語(yǔ)句(假設(shè)它存在)、生成一個(gè)值并暫停。程序在恢復(fù)執(zhí)行之前不會(huì)知道yield語(yǔ)句之后沒(méi)有任何內(nèi)容,并且只能通過(guò)另一個(gè)next()調(diào)用恢復(fù)執(zhí)行。

      yield和return

      在上面的示例中,我們使用yield將值傳遞給生成器外部。我們也可以使用return(就像在普通函數(shù)中一樣);但是,使用return可以終止執(zhí)行并設(shè)置done: true。

      function * makeGen() {   yield 'Hello';   return 'Bye';   yield 'World'; }  const g = makeGen(); // g is a generator g.next(); // { value: 'Hello', done: false } g.next(); // { value: 'Bye', done: true } g.next(); // { value: undefined, done: true }

      因?yàn)閳?zhí)行不會(huì)在return語(yǔ)句上暫停,而且根據(jù)定義,在return語(yǔ)句之后不能執(zhí)行任何代碼,所以done被設(shè)置為true。

      yield:next方法的參數(shù)

      到目前為止,我們一直在使用yield傳遞生成器外部的值(并暫停其執(zhí)行)。
      然而,yield實(shí)際上是雙向的,并且允許我們將值傳遞到生成器函數(shù)中。

      function * makeGen() {   const foo = yield 'Hello world';   console.log(foo); }  const g = makeGen(); g.next(1); // { value: 'Hello world', done: false } g.next(2); // logs 2, yields { value: undefined, done: true }

      等一下。不應(yīng)該是"1"打印到控制臺(tái),但是控制臺(tái)打印的是"2"?起初,我發(fā)現(xiàn)這部分在概念上與直覺(jué)相反,因?yàn)槲翌A(yù)期的賦值foo = 1。畢竟,我們將“1”傳遞到next()方法調(diào)用中,從而生成Hello world,對(duì)嗎?
      但事實(shí)并非如此。傳遞給第一個(gè)next(…)調(diào)用的值將被丟棄。除了這似乎是ES6規(guī)范之外,實(shí)際上沒(méi)有其他原因.從語(yǔ)義上講,第一個(gè)next方法用來(lái)啟動(dòng)遍歷器對(duì)象,所以不用帶有參數(shù)。
      我喜歡這樣對(duì)程序的執(zhí)行進(jìn)行合理化:

      • 在第一個(gè)next()調(diào)用時(shí),它將一直運(yùn)行,直到遇到y(tǒng)ield 'Hello world',在此基礎(chǔ)上生成{ value: 'Hello world', done: false }和暫停。就是這么回事。正如大家所看到的,傳遞給第一個(gè)next()調(diào)用的任何值都是不會(huì)被使用的(因此被丟棄)。
      • 當(dāng)再次調(diào)用next(…)時(shí),執(zhí)行將恢復(fù)。在這種情況下,執(zhí)行需要為常量foo分配一些值(由yield語(yǔ)句決定)。因此,我們對(duì)next(2)的第二次調(diào)用賦值foo=2。程序不會(huì)在這里停止—它會(huì)一直運(yùn)行,直到遇到下一個(gè)yield或return語(yǔ)句。在本例中,沒(méi)有
      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)