1. 程式人生 > >ES6 中的生成器函式介紹

ES6 中的生成器函式介紹

提醒:本文最後更新於 1939 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

今天介紹的是 ES6 中的生成器函式(generator function),目前瀏覽器中只有 Chrome 29+ 支援它,不過還是先要在 about:flags 中「啟用實驗性JavaScript(Enable Experimental JavaScript )」。需要注意的是,Firefox 很早就提供了類似功能,但它實現的是 ES4 語法,最後會介紹。

定義生成器函式

在 ES6 中定義一個生成器函式很簡單,在 function 後跟上「*」即可:

function* foo1() { };
function
*foo2()
{ }; function * foo3() { }; foo1.toString(); // "function* foo1() { }" foo2.toString(); // "function* foo2() { }" foo3.toString(); // "function* foo3() { }" foo1.constructor; // function GeneratorFunction() { [native code] }

呼叫生成器函式會產生一個生成器(generator)。生成器擁有的最重要的方法是 next(),用來迭代:

function* foo() { };
var
bar = foo(); bar.next(); // Object {value: undefined, done: true}

上面第 2 行的語句看上去是函式呼叫,但這時候函式程式碼並沒有執行;一直要等到第 3 行呼叫 next 方法才會執行。next 方法返回一個擁有 value 和 done 兩個欄位的物件。

生成器函式通常和 yield 關鍵字同時使用。函式執行到每個 yield 時都會中斷並返回 yield 的右值(通過 next 方法返回物件中的 value 欄位)。下次呼叫 next,函式會從 yield 的下一個語句繼續執行。等到整個函式執行完,next 方法返回的 done 欄位會變成 true。下面看一個簡單的例子:

function* list() {
    for(var i = 0; i < arguments.length; i++) {
        yield arguments[i];
    }
    return "done.";
}

var o = list(1, 2, 3);
o.next(); // Object {value: 1, done: false}
o.next(); // Object {value: 2, done: false}
o.next(); // Object {value: 3, done: false}
o.next(); // Object {value: "done.", done: true}
o.next(); // Error: Generator has already finished

可以看到,每次呼叫 next 方法,都會得到當前 yield 的值。函式執行完之後,再呼叫 next 方法會產生異常。

斐波那契數列

在其它語言中,生成器函式和 yield 通常會被用來演示生成斐波那契數列(前兩個數字都是 1 ,除此之外任何數字都是前兩個數之和的數列)。下面是 JavaScript 的生成器函式版本:

function* fab(max) {
    var count = 0, last = 0, current = 1;

    while(max > count++) {
        yield current;
        var tmp = current;
        current += last;
        last = tmp;
    }
}

var o = fab(10), ret, result = [];

while(!(ret = o.next()).done) {
    result.push(ret.value);
}

console.log(result); // [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

程式碼一目瞭然,不多解釋了。相比常見的遞迴實現,用生成器函式來產生斐波那契數列既高效又直觀。

結合 Promise 使用

我之前寫過一篇《非同步程式設計:when.js 快速上手》,介紹了 Promise 程式設計的一些基礎知識,沒看過的同學可以點過去看完再回來。實際上,生成器函式可以很好的跟 Promise 規範結合起來完成非同步程式設計。直接看例子(在瀏覽器中預覽):

var getData = function() {
    var deferred = Q.defer();

    $.getJSON(api, function(data){
        deferred.resolve(data[0]);
    });

    return deferred.promise;
}

var getImg = function(src) {
    var deferred = Q.defer();

    var img = new Image();

    img.onload = function() {
        deferred.resolve(img);
    };

    img.src = src;

    return deferred.promise;
}

var showImg = function(img) {
    $(img).appendTo($('#container'));
}

var all = Q.async(function* () {
    var src = yield getData();
    var img = yield getImg(src);
    showImg(img);
});

all();

前三個函式跟我之前那篇文章裡唯一不同的地方是:when.js 換成了 Q,因為 Q 框架的 async 方法支援生成器函式。關鍵程式碼在最後幾行,Q.async 收到生成器函式,先在內部產生一個生成器;再呼叫生成器的 next() 方法,得到類似這樣的返回值: {'value' : promise / value, 'done' : true / false} ;如果 value 是 promise,Q 會把它放在 when 函式裡執行。Q.async 內部每個 promise 在 resolve 時都會呼叫生成器的 next 方法,直到整個生成器執行完成。

最後

在其它語言中,一般都有方便的迭代器語法,自動呼叫生成器的 next 方法。例如下面是 Python 的「for ... in」:

def fab(max): 
    count, last, current = 0, 0, 1 
    while count < max: 
        yield current
        last, current = current, last + current 
        count = count + 1

for n in fab(10):
    print(n)

ES6 也規定了類似的語法「for ... of」用來迭代,現階段的 Chrome 並不支援(已經支援),Firefox 卻支援。看一個只能執行在 Firefox 下的例子(再次說明:現階段 Firefox 的生成器函式未按 ES6 規範實現):

function fab(max) {
    var count = 0, last = 0, current = 1;

    while(count++ < max) {
        yield current;
        var tmp = current;
        current += last;
        last = tmp;
    }
}

for(var i of fab(10)) {
    console.log(i);
}

參考:

--EOF--

提醒:本文最後更新於 1939 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

相關推薦

ES6 生成器函式介紹

提醒:本文最後更新於 1939 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 今天介紹的是 ES6 中的生成器函式(generator function),目前瀏覽器中只有 Chrome 29+ 支援它,不過還是先要在 about:flags 中「啟用實驗性JavaScript(Enabl

ES6函式和陣列補漏

物件的函式解構 我們在前後端分離時,後端經常返回來JSON格式的資料,前端的美好願望是直接把這個JSON格式資料當作引數,傳遞到函式內部進行處理。ES6就為我們提供了這樣的解構賦值。 let json={ a:'leiy', b:'ly' } function fun({a,b="yu"})

三十四、ES6箭頭函式的使用

1、單引數箭頭函式 ES6中允許使用“箭頭”(=>)定義函式: var f = v => v; 以上程式碼相當於: var f = function( v ) { return v; } “箭頭”(=>)後面是函式體,“箭頭”(=>

續(利用tensorflow實現簡單的卷積神經網路-對程式碼相關函式介紹)——遷移學習小記(三)

  上篇文章對cnn進行了一些介紹,附了完整小例子程式碼,介紹了一部分函式概念,但是對我這樣的新手來說,程式碼中涉及的部分函式還是無法一下子全部理解。於是在本文中將對程式碼中使用的函式繼續進行一一介紹。 具體程式碼見上一篇(二) 一、 #定義輸入的placehoder,x是特徵

es6箭頭函式 注意點

var aaabbb = 'kkkooo' setTimeout(()=>{ var aaaa = 'kkkk'; console.log(this) },1000); 因為據我瞭解,箭頭函式指向是建立時候上下文的this指向,所以天真的認為上述函式中在箭頭函式內部建立的變數

標頭檔案管理 使用#ifndef防止多重包含 部分標頭檔案用途及其函式介紹

       1、 在同一個檔案中只能將同一個標頭檔案包含一次。記住這個規則很容易,但很可能在不知情的情況下將標頭檔案包含多次。例如,可能使用包含了另一個頭檔案的標頭檔案。有一種標準的C++技術可以避免多次包含同一個標頭檔案。它是基於前處理器編譯指令#ifnd

影象處理矩形標記影象某一塊區域matlabrectangle函式介紹

rectangle('Position',[x,y,w,h]) 從點(x,y)開始繪製一個寬w高h的矩形,對座標軸資料單元指定值。 注意,按指定的比例顯示矩形,需要設定座標軸資料寬高比來使得x和y軸有等長的單位。你可以用命令axis equal 或者daspect([1,

oracle函式介紹(一):nvl函式、decode函式、case when函式、sum函式

最近做專案接觸到的oracle資料庫比較多,經常用到裡面的一些函式,以前的部落格中也介紹過行轉列和列轉行,這次再簡單給大家介紹幾個: nvl() NVL(a,b)就是判斷a是否是NULL,如果不

ES5,ES6箭頭函式,物件定義this的總結

最近在學ES6的時候,發現使用箭頭函式的時候的this指向不太清楚,和普通的物件建立做了一些對比,講講自己的理解,有問題希望大家和我一起討論研究 箭頭函式 和 function(){}定義的區別,箭頭函式的 這裡的所有程式碼基於chrome進行測試  這裡有幾個帖子是作為參考的

阿里前端測試題--關於ES6Promise函式的理解與應用

今天做了阿里前端的筆試題目,原題目是這樣的 //實現mergePromise函式,把傳進去的陣列順序先後執行,//並且把返回的資料先後放到陣列data中const timeout = ms => new Promise((resolve, reject) => {setTimeout(() =

ES6箭頭函式的使用

基本用法 ES6允許使用“箭頭”(=>)定義函式。 var f = v => v; 上面的箭頭函式等同於: var f = function(v) {  return v;  }; 如果箭頭函式不需要引數或需要多個引數,就使用一個圓括號代表引數部

Python生成器和叠代器的功能介紹

family line 介紹 mil auto 叠代器 常用 方法 lean 生成器和叠代器的功能介紹 1. 生成器(generator) 1. 賦值生成器 1. 創建 方法:x = (varia

es6的(=>)箭頭函式

x => x * x 上面的箭頭函式相當於: function (x) { return x * x; } 箭頭函式相當於匿名函式,並且簡化了函式定義。 箭頭函式有兩種格式,一種像上面的,只包含一個表示式,連{ ... }和return都省略掉了。 還有一種可以包含多條語句,這時候就不能省

Es6Map物件和Set物件的介紹及應用

map和set的方法,工作中有使用到,所以學習一下:   Map 物件 Map 物件儲存鍵值對。任何值(物件或者原始值) 都可以作為一個鍵或一個值。 var myMap = new Map(); myMap.set("bar", "baz"); myMap.set(1, "foo"

tensorflow的control_flow_ops.switch函式介紹

tensorflow中的control_flow_ops模組屬於tensorflow.python.ops中的一個模組,從switch函式的名稱上看就是一個開關函式。 函式:control_flow_ops.switch(data,pred,dtype=None,name=None) 功

ES6的高階函式:如同 a => b => c 一樣簡單

ES6來啦!隨著越來越多的程式碼庫和思潮引領者開始在他們的程式碼中使用ES6,以往被認為是“僅需瞭解”的ES6特性變成了必需的程式碼常識。這不僅僅是新的語法學習 - 在許多範例中, ES6中新的語言特性可以讓在ES5中寫起來非常麻煩的表達變得更加簡

ES6的箭頭函式和普通函式有什麼區別?

1、普通函式中的this總是指向呼叫它的那個物件,    箭頭函式沒有自己的this,他的this永遠指向其定義環境,任何方法都改變不了其指向,如call()、bind()、apply()。(正是因為它沒有this,所以也就不能用作建構函式,也沒有原型物件) 2、箭頭函式不能當作建構函

ES6或ES7 async函式的用法,通過一段程式碼理解它的用法

ES6或ES7 中async函式的用法,一行一行看完程式碼和後面的解釋,應該就會用了吧 首先,如果不懂Promise的用法,那可能你看不懂這裡寫的async的用法。 上面是async使用例子,async是非同步操作的新方案,asyncPrint函式中第21行的

javascript的一般函式ES6的箭頭函式對比,以及this指向問題的深度理解

關於this的指向問題,老外有文章寫得非常棒,在看了老外的文章 並結合自己的想法再修改此篇文章 一 、基本概念 本文定義的一般函式 單純 指的是js原生函式(ES5函式) 同時ES5中的作用域只有全域

javascript 的立即呼叫函式模式、閉包及es6的塊級作用域

先來看一個在牛客上看到的面試題: 這裡一開始會以為是不就是隔1秒輸出i的值嗎,最後結果就是輸出0~9 的十個數字呀,真的是太young了。 但是真是擼了一遍程式碼,控制檯輸出刺眼的10個10,what? 這個查了資料是說因為這個函式為每一個i都設定了一個計時器,那麼