ES6中的yield

yield 關鍵字用來暫停和恢復一個生成器函數((function* 或遺留的生成器函數)。web

語法

[rv] = yield [expression];
複製代碼

expression 定義經過迭代器協議從生成器函數返回的值。若是省略,則返回undefined。express

rv 返回傳遞給生成器的next()方法的可選值,以恢復其執行。瀏覽器

描述

  • yield關鍵字使生成器函數執行暫停,yield關鍵字後面的表達式的值返回給生成器的調用者。它能夠被認爲是一個基於生成器的版本的return關鍵字。bash

  • yield關鍵字實際返回一個IteratorResult對象,它有兩個屬性,value和done。value屬性是對yield表達式求值的結果,而done是false,表示生成器函數還沒有徹底完成。app

  • 一旦遇到 yield 表達式,生成器的代碼將被暫停運行,直到生成器的 next() 方法被調用。每次調用生成器的next()方法時,生成器都會恢復執行,直到達到如下某個值:函數

    • yield,致使生成器再次暫停並返回生成器的新值。 下一次調用next()時,在yield以後緊接着的語句繼續執行。
    • throw用於從生成器中拋出異常。這讓生成器徹底中止執行,並在調用者中繼續執行,正如一般狀況下拋出異常同樣。
    • 到達生成器函數的結尾;在這種狀況下,生成器的執行結束,而且IteratorResult給調用者返回undefined而且done爲true。
    • 到達return 語句。在這種狀況下,生成器的執行結束,並將IteratorResult返回給調用者,其值是由return語句指定的,而且done 爲true。
  • 若是將參數傳遞給生成器的next()方法,則該值將成爲生成器當前yield操做返回的值。ui

  • 在生成器的代碼路徑中的yield運算符,以及經過將其傳遞給Generator.prototype.next()指定新的起始值的能力之間,生成器提供了強大的控制力。spa

說明

  • yield並不能直接生產值,而是產生一個等待輸出的函數
  • 除IE外,其餘全部瀏覽器都可兼容(包括win10 的Edge)
  • 某個函數包含了yield,意味着這個函數已是一個Generator
  • 若是yield在其餘表達式中,須要用()單獨括起來
  • yield表達式自己沒有返回值,或者說老是返回undefined(由next返回)
  • next()可無限調用,但既定循環完成以後老是返回undeinded

next()

  • next()能夠帶一個參數,該參數會被認爲是上一個yield總體的返回值,稍後將在代碼中展現。prototype

  • 能夠在不一樣階段從外部直接向內部注入不一樣的值來調整函數的行爲(這一點是其餘循環很難作到的,或要付出較大的代價才能夠作到)code

簡單例子

function* countAppleSales () {
  var saleList = [3, 7, 5];
  for (var i = 0; i < saleList.length; i++) {
    yield saleList[i];
  }
}

var appleStore = countAppleSales(); 
console.log(appleStore); // Generator { }
console.log(appleStore.next(countAppleSales())); // { value: 3, done: false }
console.log(appleStore.next()); // { value: 7, done: false }
console.log(appleStore.next()); // { value: 5, done: false }
console.log(appleStore.next()); // { value: undefined, done: true }
複製代碼

參數對比

function* countAppleSales(){
    for(var i=0; true; i++){
        var reset = yield i;
        if(reset){
            i = -1;
        }
    }
}

var appleStore = countAppleSales();
console.log(appleStore.next()); //{ value: 0, done: false }
console.log(appleStore.next()); //{ value: 1, done: false }
console.log(appleStore.next()); //{ value: 2, done: false }
console.log(appleStore.next(true)); //{ value: 0, done: false }
console.log(appleStore.next()); //{ value: 1, done: false }
console.log(appleStore.next()); //{ value: 2, done: false }
複製代碼
  1. 調用next(),會產生許多i的值, 可是不會影響reset,由於yield直接將值return出來了。
  2. 當傳值true後,yield及他的參數總體變爲true賦值給reset,這是reset會被執行,從而知足循環內的判斷條件
  3. 不會平白增長循環的時間複雜度,由於不傳參的時候,並不會佔用更多的內存

深刻理解

function* test(x){
    var y = 2 * (yield (x + 1));
    var z = yield(y/3);
    console.log("x=" + x + ",y=" + y + ",z=" + z);
    return (x + y + z);
}

var a = test(5);
a.next(); //{ value: 6, done: false }
a.next(); //{ value: NaN, done: false }
a.next(); //x=5,y=NaN,z=undefined web-517059656c042747f821.js:1:478047
          //{ value: NaN, done: true }
a.next();{ value: undefined, done: true }

var b = test(5);
b.next(); //{ value: 6, done: false }
b.next(12); //{ value: 8, done: false }
b.next(13); //x=5,y=24,z=13 web-517059656c042747f821.js:1:478047
            //{ value: 42, done: true }
b.next(); //{ value: undefined, done: true }
複製代碼

A組

  1. x恆爲5,因此第一次調用傳空沒問題,可獲得對應的第一個yield返回值:yield (x + 1)
  2. 第二次調用,無參數傳入,因此y爲NaN(2* undefined),天然得不到z
  3. 第三次調用同上分析

B組

  1. x恆爲5,因此第一次調用傳空沒問題,可獲得對應的第一個yield返回值:yield (x + 1)
  2. 第二次調用,傳入12,因此y爲24(yield (x + 1)=入參),獲得第二個yield: yield (y / 3)=8
  3. 第三次調用同上分析,獲得最後的z值並return=42

參考文章:

MDN yield

深刻理解js中的yield

相關文章
相關標籤/搜索