成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

es6 generator函數(shù)

voidking / 1095人閱讀

摘要:返回的遍歷器對(duì)象可以依次遍歷函數(shù)內(nèi)部的每一個(gè)狀態(tài)。示例內(nèi)部捕獲外部捕獲內(nèi)部捕獲外部捕獲上面代碼遍歷器對(duì)象連續(xù)拋出兩個(gè)錯(cuò)誤,第一個(gè)被函數(shù)體內(nèi)的捕獲。上面代碼中,首先執(zhí)行函數(shù),獲取遍歷器對(duì)象,然后使用方法第二行,執(zhí)行異步任務(wù)的第一階段。

參考 來(lái)源《ecmascript6 入門(mén)》generator部分

認(rèn)識(shí)generator函數(shù)

形式上,generator函數(shù)有兩個(gè)特點(diǎn):一是function關(guān)鍵字與函數(shù)名之間有一個(gè)*。二是函數(shù)體內(nèi)使用yield語(yǔ)句,如下代碼。(yield在英語(yǔ)中意思就是 產(chǎn)出)

function* helloWorld(){
    yield ‘hello’;
    yield ‘world’;
    return ‘ending’;
}

var hw=helloWorld();

調(diào)用執(zhí)行,調(diào)用generator函數(shù)和調(diào)用普通函數(shù)的形式一樣,沒(méi)有區(qū)別,比如上面helloWorld()。
但是內(nèi)部的執(zhí)行與普通函數(shù)是完全不同,調(diào)用generator函數(shù)之后,該函數(shù)并不執(zhí)行,返回的也不是函數(shù)運(yùn)行結(jié)果,而是一個(gè)指向內(nèi)部狀態(tài)的指針對(duì)象,也就是遍歷器對(duì)象。也就是說(shuō)generator函數(shù)還是一個(gè)遍歷器對(duì)象生成函數(shù)。返回的遍歷器對(duì)象可以依次遍歷generator函數(shù)內(nèi)部的每一個(gè)狀態(tài)。

它是怎么遍歷的呢?。遍歷器對(duì)象每次調(diào)用next方法,內(nèi)部指針就從函數(shù)頭部或者上一次停下來(lái)的的地方開(kāi)始執(zhí)行,遇到y(tǒng)ield語(yǔ)句暫停并返回一個(gè)對(duì)象,下一次調(diào)用next,遇到下一個(gè)yield暫停并返回一個(gè)對(duì)象(對(duì)象擁有value,和done屬性)。value的值就是yield語(yǔ)句的值,done屬性表示遍歷是否結(jié)束(false沒(méi)有結(jié)束,true結(jié)束)。

上面示例代碼用調(diào)用4次next:

第一次調(diào)用next,generator函數(shù)開(kāi)始執(zhí)行,遇到第一個(gè)yield暫停,并且返回一個(gè)對(duì)象,value =hello,done=false表示還遍歷還沒(méi)有結(jié)束。

第二次調(diào)用next,從上次暫停的位置開(kāi)始執(zhí)行,遇到下一個(gè)yield暫停,并返回一個(gè)對(duì)象。。

第三次調(diào)用next,返回value為return的值,done為true表示遍歷結(jié)束。

第四次調(diào)用next,generator函數(shù)已經(jīng)運(yùn)行完畢,返回value為undefined,done為true。

yield和return;

yield語(yǔ)句與return語(yǔ)句既有相似之處 ,也有區(qū)別。相似之處在于都可以返回緊跟在其后邊的表達(dá)式的值。區(qū)別在于每次遇到y(tǒng)ield,函數(shù)暫停,下一次在從該位置向后執(zhí)行,而return語(yǔ)句沒(méi)有此位置記憶功能,一個(gè)函數(shù)里面只能執(zhí)行一次,而yield正因?yàn)榭梢杂卸鄠€(gè),可以返回多個(gè)值,所以generator函數(shù)可以返回一系列的值,這也就是它名稱(chēng)的來(lái)歷(generator英語(yǔ)意思為生成器)

與Iterator接口的關(guān)系

任意一個(gè)對(duì)象的iterator接口都是部署在了Symbol.iterator屬性,由于generator函數(shù)就是遍歷器生成函數(shù),所以可以直接把它賦值給Symbol.iterator,從而使的該對(duì)象具有Iterator接口。

示例:

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

[...myIterable] // [1, 2, 3]

說(shuō)明:代碼中generator函數(shù)賦給了myIterable對(duì)象的Symbol.iterator屬性,使的該對(duì)象具有iterator接口,可以 被()運(yùn)算符遍歷。為什么是這樣?(…)三個(gè)點(diǎn)這里叫做擴(kuò)展運(yùn)算符,它的執(zhí)行是調(diào)用了遍歷器方法(它可以將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分割的序列,可以用于函數(shù)調(diào)用傳參),這里就是generator函數(shù),然后返回一個(gè)遍歷器對(duì)象,然后重復(fù)調(diào)用它的next方法。其實(shí)不只有擴(kuò)展運(yùn)算符,for..of循環(huán)的執(zhí)行也是調(diào)用的iterator接口方法,也就是說(shuō)只有部署了iterator接口的數(shù)據(jù)集合才可以使用for...of,擴(kuò)展運(yùn)算符遍歷。

Generator.prototype.throw()

Generator函數(shù)返回的遍歷器對(duì)象,都有一個(gè)throw方法,可以在函數(shù)體外拋出錯(cuò)誤,然后在Generator函數(shù)體內(nèi)捕獲。

示例:

var g = function* () {
  try {
    yield;
  } catch (e) {
    console.log("內(nèi)部捕獲", e);
  }
};

var i = g();
i.next();

try {
  i.throw("a");
  i.throw("b");
} catch (e) {
  console.log("外部捕獲", e);
}
// 內(nèi)部捕獲 a
// 外部捕獲 b

上面代碼遍歷器對(duì)象連續(xù)拋出兩個(gè)錯(cuò)誤,第一個(gè)被generator函數(shù)體內(nèi)的catch捕獲。第二個(gè)由于generator函數(shù)體內(nèi)的catch已經(jīng)執(zhí)行過(guò)了,所以被外面的catch捕獲。如果generator函數(shù)體內(nèi)沒(méi)有try...catch...語(yǔ)句,那么就會(huì)被外面的catch語(yǔ)句捕獲。如果都沒(méi)有try...catch...,那么程序報(bào)錯(cuò)。

5.Generator.prototype.return()

yield*語(yǔ)句

如果在 Generator 函數(shù)內(nèi)部,調(diào)用另一個(gè) Generator 函數(shù),默認(rèn)情況下是沒(méi)有效果的。yield*語(yǔ)句可以用來(lái)在一個(gè) Generator 函數(shù)里面執(zhí)行另一個(gè) Generator 函數(shù)。

function* foo() {
  yield "a";
  yield "b";
}

function* bar() {
  yield "x";
  yield* foo();
  yield "y";
}

// 等同于
function* bar() {
  yield "x";
  yield "a";
  yield "b";
  yield "y";
}

// 等同于
function* bar() {
  yield "x";
  for (let v of foo()) {
    yield v;
  }
  yield "y";
}

for (let v of bar()){
  console.log(v);
}
// "x"
// "a"
// "b"
// "y"

從語(yǔ)法角度看,如果yield命令后面跟的是一個(gè)遍歷器對(duì)象,需要在yield命令后面加上星號(hào),表明它返回的是一個(gè)遍歷器對(duì)象。這被稱(chēng)為yield*語(yǔ)句。

let delegatedIterator = (function* () {
  yield "Hello!";
  yield "Bye!";
}());

let delegatingIterator = (function* () {
  yield "Greetings!";
  yield* delegatedIterator;
  yield "Ok, bye.";
}());

for(let value of delegatingIterator) {
  console.log(value);
}
// "Greetings!
// "Hello!"
// "Bye!"
// "Ok, bye.”

yield*后面的Generator函數(shù)(沒(méi)有return語(yǔ)句時(shí)),等同于在Generator函數(shù)內(nèi)部,部署一個(gè)for...of循環(huán)。

function* concat(iter1, iter2) {
  yield* iter1;
  yield* iter2;
}

// 等同于

function* concat(iter1, iter2) {
  for (var value of iter1) {
    yield value;
  }
  for (var value of iter2) {
    yield value;
  }
}

上面代碼,yield* 執(zhí)行的是一個(gè)遍歷器,for...of...循環(huán)的也是一個(gè)遍歷器,所以for...of...返回yield value時(shí)等同于yield*

兩個(gè)平常會(huì)用到的示例:

1)遍歷嵌套的數(shù)組:

function* iterTree(tree) {
  if (Array.isArray(tree)) {
    for(let i=0; i < tree.length; i++) {
      yield* iterTree(tree[i]);
    }
  } else {
    yield tree;
  }
}

const tree = [ "a", ["b", "c"], ["d", "e"] ];

for(let x of iterTree(tree)) {
  console.log(x);
}
// a
// b
// c
// d
// e

2)對(duì)于狀態(tài)的控制:

var clock = function*() {
  while (true) {
    console.log("Tick!");
    yield;
    console.log("Tock!");
    yield;
  }
};
作為對(duì)象屬性的generator

如果一個(gè)對(duì)象的屬性是**Generator**函數(shù),可以簡(jiǎn)寫(xiě)成下面的形式

let obj = {
  * myGeneratorMethod() {
    ···
  }
};

等同于

let obj = {
  myGeneratorMethod: function* () {
    // ···
  }
};
Generator函數(shù)的this

Generator函數(shù)總是返回一個(gè)遍歷器,ES6規(guī)定這個(gè)遍歷器是Generator函數(shù)的實(shí)例,也繼承了Generator函數(shù)的prototype對(duì)象上的方法。

function* g() {}

g.prototype.hello = function () {
  return "hi!";
};

let obj = g();

obj instanceof g // true
obj.hello() // "hi!"

上面代碼表明,Generator函數(shù)g返回的遍歷器obj,是g的實(shí)例,而且繼承了g.prototype。但是,如果把g當(dāng)作普通的構(gòu)造函數(shù),并不會(huì)生效,因?yàn)間返回的總是遍歷器對(duì)象,而不是this對(duì)象。所以如果在generator函數(shù)內(nèi)使用this,obj對(duì)象訪問(wèn)不到。

那么,有沒(méi)有辦法讓Generator函數(shù)返回一個(gè)正常的對(duì)象實(shí)例,既可以用next方法,又可以獲得正常的this?

function* F() {
  this.a = 1;
  yield this.b = 2;
  yield this.c = 3;
}
var f = F.call(F.prototype);

f.next();  // Object {value: 2, done: false}
f.next();  // Object {value: 3, done: false}
f.next();  // Object {value: undefined, done: true}

f.a // 1
f.b // 2
f.c // 3

上面代碼:首先使用call函數(shù)將F函數(shù)的this綁定到F.prototype;而f還是那個(gè)遍歷器對(duì)象是F函數(shù)的實(shí)例,又可以繼承F.prototype的屬性,所以也就可以訪問(wèn)F.prototype代表的this的屬性了。

Generator函數(shù)的應(yīng)用

generator函數(shù)最大的作用可以用作異步任務(wù)的封裝(由于它的yield命令特性,可以暫停和恢復(fù)執(zhí)行)。而之前javascript對(duì)于異步的實(shí)現(xiàn)主要就是 回調(diào)函數(shù),事件監(jiān)聽(tīng),promise等。

示例:

var fetch = require("node-fetch");

function* gen(){
  var url = "https://api.github.com/users/github";
  var result = yield fetch(url);
  console.log(result.bio);
}

上面代碼中,Generator 函數(shù)封裝了一個(gè)異步操作,該操作先讀取一個(gè)遠(yuǎn)程接口,然后從 JSON 格式的數(shù)據(jù)解析信息。就像前面說(shuō)過(guò)的,這段代碼非常像同步操作,除了加上了yield命令。

var g = gen();
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});

上面代碼中,首先執(zhí)行 Generator 函數(shù),獲取遍歷器對(duì)象,然后使用next方法(第二行),執(zhí)行異步任務(wù)的第一階段。由于Fetch模塊返回的是一個(gè) Promise 對(duì)象,而這個(gè)對(duì)象被yield返回到了它的value屬性中,因此要用.value.then方法調(diào)用then方法。成功后 return數(shù)據(jù)參數(shù)data可以被第二個(gè)then方法中接受。而第二次調(diào)用then方法傳入的data又傳回了gen函數(shù)給了變量result。value往出傳值,next可以往里傳值。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82147.html

相關(guān)文章

  • ES6學(xué)習(xí)筆記之Generator函數(shù)

    摘要:調(diào)用函數(shù)后和普通函數(shù)不同的是,該函數(shù)并不立即執(zhí)行,也不返回函數(shù)執(zhí)行結(jié)果,而是返回一個(gè)指向內(nèi)部狀態(tài)的對(duì)象,也可以看作是一個(gè)遍歷器對(duì)象。第一個(gè)只是用來(lái)啟動(dòng)函數(shù)內(nèi)部的遍歷器,傳參也沒(méi)有多大意義。 之前斷斷續(xù)續(xù)接觸到了一些ES6的知識(shí),異步編程方面聽(tīng)得比較多的就是Promise,直到最近比較系統(tǒng)地學(xué)習(xí)了ES6的新特性才發(fā)現(xiàn)Generator這個(gè)神奇的存在,它可以實(shí)現(xiàn)一些前所未有的事情,讓我頓時(shí)...

    cjie 評(píng)論0 收藏0
  • 深入理解 Generator 函數(shù)

    摘要:同時(shí),迭代器有一個(gè)方法來(lái)向函數(shù)中暫停處拋出一個(gè)錯(cuò)誤,該錯(cuò)誤依然可以通過(guò)函數(shù)內(nèi)部的模塊進(jìn)行捕獲處理。 本文翻譯自:Diving Deeper With ES6 Generators 由于個(gè)人能力有限,翻譯中難免有紕漏和錯(cuò)誤,望不吝指正issue ES6 Generators:完整系列 The Basics Of ES6 Generators Diving Deeper With E...

    jzzlee 評(píng)論0 收藏0
  • 關(guān)于協(xié)程和 ES6 中的 Generator

    摘要:關(guān)于協(xié)程和中的什么是協(xié)程進(jìn)程和線程眾所周知,進(jìn)程和線程都是一個(gè)時(shí)間段的描述,是工作時(shí)間段的描述,不過(guò)是顆粒大小不同,進(jìn)程是資源分配的最小單位,線程是調(diào)度的最小單位。子程序就是協(xié)程的一種特例。 關(guān)于協(xié)程和 ES6 中的 Generator 什么是協(xié)程? 進(jìn)程和線程 眾所周知,進(jìn)程和線程都是一個(gè)時(shí)間段的描述,是CPU工作時(shí)間段的描述,不過(guò)是顆粒大小不同,進(jìn)程是 CPU 資源分配的最小單位,...

    RyanHoo 評(píng)論0 收藏0
  • 【W(wǎng)eb全棧課程三】ES6特性介紹(下)

    摘要:示例運(yùn)行函數(shù)彈出彈出函數(shù)接收參數(shù),返回值。其中,返回一個(gè)對(duì)象,是的返回值,代表函數(shù)是否執(zhí)行完成。 ES6特性介紹(下) ES6新的標(biāo)準(zhǔn),新的語(yǔ)法特征:1、變量/賦值2、函數(shù)3、數(shù)組/json4、字符串5、面向?qū)ο?、Promise7、generator8、ES7:async/await 《【W(wǎng)eb全棧課程二】ES6特性介紹(上)》見(jiàn):https://segmentfault.com/a...

    wangshijun 評(píng)論0 收藏0
  • ES6新特性 iterators and Generators

    摘要:在函數(shù)定義上使用關(guān)鍵字來(lái)表示方法調(diào)用時(shí)返回的值。是一個(gè)有屬性的。這個(gè)指向一個(gè)函數(shù),這個(gè)函數(shù)返回關(guān)于這個(gè)對(duì)象的。在中所有的集合類(lèi)對(duì)象和字符串都是,并且有自己默認(rèn)的。注意本身是不返回任何值的,它只向外部產(chǎn)生值。 ES6新特性 iterators and Generators ES6中引入了許多新特性,目前大量的JavaScript項(xiàng)目已經(jīng)使用了ES6來(lái)進(jìn)行開(kāi)發(fā),那么熟悉這些新的特性是十分必...

    pf_miles 評(píng)論0 收藏0
  • ES6中的異步編程:Generators函數(shù)(一)

    摘要:由于可以使用語(yǔ)句來(lái)暫停異步操作,這讓異步編程的代碼,很像同步數(shù)據(jù)流方法一樣。該臨時(shí)函數(shù)就叫做函數(shù)。下面就是簡(jiǎn)單的函數(shù)轉(zhuǎn)換器。 訪問(wèn)原文地址 對(duì)ES6的generators的介紹分為3個(gè)部分 第一部分base介紹及使用 第二部分基于generators和Promise實(shí)現(xiàn)最強(qiáng)大的異步處理邏輯 概述 Generator函數(shù)是協(xié)程在ES6的實(shí)現(xiàn),用來(lái)做異步流程的封裝,最大特點(diǎn)就是可以交出...

    ztyzz 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<