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

資訊專欄INFORMATION COLUMN

《深入理解ES6》筆記——迭代器(Iterator)和生成器(Generator)(8)

AndroidTraveler / 1838人閱讀

摘要:迭代器是一種特殊對象,每一個迭代器對象都有一個,該方法返回一個對象,包括和屬性。默認(rèn)情況下定義的對象是不可迭代的,但是可以通過創(chuàng)建迭代器。在迭代器中拋出錯誤不再執(zhí)行生成器返回語句生成器中添加表示退出操作。迭代器是一個對象。

迭代器(Iterator) ES5實現(xiàn)迭代器

迭代器是什么?遇到這種新的概念,莫慌張。

迭代器是一種特殊對象,每一個迭代器對象都有一個next(),該方法返回一個對象,包括value和done屬性。

ES5實現(xiàn)迭代器的代碼如下:

//實現(xiàn)一個返回迭代器對象的函數(shù),注意該函數(shù)不是迭代器,返回結(jié)果才叫做迭代器。
function createIterator(items) {
  var i = 0;
  return {
    next() {
      var done = (i >= items.length); // 判斷i是否小于遍歷的對象長度。
      var value = !done ? items[i++] : undefined; //如果done為false,設(shè)置value為當(dāng)前遍歷的值。
      return {
        done,
        value
      }
    }
  }
}
const a = createIterator([1, 2, 3]);

//該方法返回的最終是一個對象,包含value、done屬性。
console.log(a.next()); //{value: 1, done: false}
console.log(a.next()); //{value: 2, done: false}
console.log(a.next()); //{value: 3, done: false}
console.log(a.next()); //{value: undefined, done: true}
生成器(Generator)

生成器是函數(shù):用來返回迭代器。

這個概念有2個關(guān)鍵點,一個是函數(shù)、一個是返回迭代器。這個函數(shù)不是上面ES5中創(chuàng)建迭代器的函數(shù),而是ES6中特有的,一個帶有*(星號)的函數(shù),同時你也需要使用到y(tǒng)ield。

//生成器函數(shù),ES6內(nèi)部實現(xiàn)了迭代器功能,你要做的只是使用yield來迭代輸出。
function *createIterator() {
  yield 1;
  yield 2;
  yield 3;
}
const a = createIterator();
console.log(a.next()); //{value: 1, done: false}
console.log(a.next()); //{value: 2, done: false}
console.log(a.next()); //{value: 3, done: false}
console.log(a.next()); //{value: undefined, done: true}

生成器的yield關(guān)鍵字有個神奇的功能,就是當(dāng)你執(zhí)行一次next(),那么只會執(zhí)行一個yield后面的內(nèi)容,然后語句終止運行。

在for循環(huán)中使用迭代器

即使你是在for循環(huán)中使用yield關(guān)鍵字,也會暫停循環(huán)。

function *createIterator(items) {
  for(let i = 0; i < items.length;  i++) {
    yield items[i]
  }
}
const a = createIterator([1, 2, 3]);
console.log(a.next()); //{value: 1, done: false}
yield使用限制

yield只可以在生成器函數(shù)內(nèi)部使用,如果在非生成器函數(shù)內(nèi)部使用,則會報錯。

function *createIterator(items) {
    //你應(yīng)該在這里使用yield
  items.map((value, key) => {
    yield value //語法錯誤,在map的回調(diào)函數(shù)里面使用了yield
  })
}
const a = createIterator([1, 2, 3]);
console.log(a.next()); //無輸出
生成器函數(shù)表達(dá)式

函數(shù)表達(dá)式很簡單,就是下面這種寫法,也叫匿名函數(shù),不用糾結(jié)。

const createIterator = function *() {
    yield 1;
    yield 2;
}
const a = createIterator();
console.log(a.next());
在對象中添加生成器函數(shù)

一個對象長這樣:

const obj = {}

我們可以在obj中添加一個生成器,也就是添加一個帶星號的方法:

const obj = {
  a: 1,
  *createIterator() {
    yield this.a
  }
}
const a = obj.createIterator();
console.log(a.next());  //{value: 1, done: false}
可迭代對象和for of循環(huán)

再次默讀一遍,迭代器是對象,生成器是返回迭代器的函數(shù)。

凡是通過生成器生成的迭代器,都是可以迭代的對象(可迭代對象具有Symbol.iterator屬性),也就是可以通過for of將value遍歷出來。

function *createIterator() {
  yield 1;
  yield 2;
  yield 3;
}
const a = createIterator();
for(let value of a) {
  console.log(value)
}
// 1 2 3

上面的例子告訴我們生成器函數(shù)返回的迭代器是一個可以迭代的對象。其實我們這里要研究的是Symbol.iterator的用法。

function *createIterator() {
  yield 1;
  yield 2;
  yield 3;
}
const a = createIterator(); //a是一個迭代器
const s = a[Symbol.iterator]();//使用Symbol.iterator訪問迭代器
console.log(s.next()) //{value: 1, done: false}

Symbol.iterator還可以用來檢測一個對象是否可迭代:

typeof obj[Symbol.iterator] === "function"
創(chuàng)建可迭代對象

在ES6中,數(shù)組、Set、Map、字符串都是可迭代對象。

默認(rèn)情況下定義的對象(object)是不可迭代的,但是可以通過Symbol.iterator創(chuàng)建迭代器。

const obj = {
  items: []
}
obj.items.push(1);//這樣子雖然向數(shù)組添加了新元素,但是obj不可迭代
for (let x of obj) {
  console.log(x) // _iterator[Symbol.iterator] is not a function
}

//接下來給obj添加一個生成器,使obj成為一個可以迭代的對象。
const obj = {
  items: [],
  *[Symbol.iterator]() {
    for (let item of this.items) {
      yield item;
    }
  }
}
obj.items.push(1)
//現(xiàn)在可以通過for of迭代obj了。
for (let x of obj) {
  console.log(x)
}
內(nèi)建迭代器

上面提到了,數(shù)組、Set、Map都是可迭代對象,即它們內(nèi)部實現(xiàn)了迭代器,并且提供了3種迭代器函數(shù)調(diào)用。

1、entries() 返回迭代器:返回鍵值對

//數(shù)組
const arr = ["a", "b", "c"];
for(let v of arr.entries()) {
  console.log(v)
}
// [0, "a"] [1, "b"] [2, "c"]

//Set
const arr = new Set(["a", "b", "c"]);
for(let v of arr.entries()) {
  console.log(v)
}
// ["a", "a"] ["b", "b"] ["c", "c"]

//Map
const arr = new Map();
arr.set("a", "a");
arr.set("b", "b");
for(let v of arr.entries()) {
  console.log(v)
}
// ["a", "a"] ["b", "b"]

2、values() 返回迭代器:返回鍵值對的value

//數(shù)組
const arr = ["a", "b", "c"];
for(let v of arr.values()) {
  console.log(v)
}
//"a" "b" "c"

//Set
const arr = new Set(["a", "b", "c"]);
for(let v of arr.values()) {
  console.log(v)
}
// "a" "b" "c"

//Map
const arr = new Map();
arr.set("a", "a");
arr.set("b", "b");
for(let v of arr.values()) {
  console.log(v)
}
// "a" "b"

3、keys() 返回迭代器:返回鍵值對的key

//數(shù)組
const arr = ["a", "b", "c"];
for(let v of arr.keys()) {
  console.log(v)
}
// 0 1 2

//Set
const arr = new Set(["a", "b", "c"]);
for(let v of arr.keys()) {
  console.log(v)
}
// "a" "b" "c"

//Map
const arr = new Map();
arr.set("a", "a");
arr.set("b", "b");
for(let v of arr.keys()) {
  console.log(v)
}
// "a" "b"

雖然上面列舉了3種內(nèi)建的迭代器方法,但是不同集合的類型還有自己默認(rèn)的迭代器,在for of中,數(shù)組和Set的默認(rèn)迭代器是values(),Map的默認(rèn)迭代器是entries()。

for of循環(huán)解構(gòu)

對象本身不支持迭代,但是我們可以自己添加一個生成器,返回一個key,value的迭代器,然后使用for of循環(huán)解構(gòu)key和value。

const obj = {
  a: 1,
  b: 2,
  *[Symbol.iterator]() {
    for(let i in obj) {
      yield [i, obj[i]]
    }
  }
}
for(let [key, value] of obj) {
  console.log(key, value)
}
// "a" 1, "b" 2
字符串迭代器
const str = "abc";
for(let v of str) {
  console.log(v)
}
// "a" "b" "c"
NodeList迭代器

迭代器真是無處不在啊,dom節(jié)點的迭代器你應(yīng)該已經(jīng)用過了。

const divs = document.getElementByTagName("div");
for(let d of divs) {
  console.log(d)
}
展開運算符和迭代器
const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [...a, ...b]
console.log(c) // [1, 2, 3, 4, 5, 6]

高級迭代器功能

你說什么?上面講了一堆廢話都是基礎(chǔ)功能?還有高級功能沒講?

高級功能不復(fù)雜,就是傳參、拋出異常、生成器返回語句、委托生成器。

1、傳參

生成器里面有2個yield,當(dāng)執(zhí)行第一個next()的時候,返回value為1,然后給第二個next()傳入?yún)?shù)10,傳遞的參數(shù)會替代掉上一個next()的yield返回值。在下面的例子中就是first。

function *createIterator() {
  let first = yield 1;
  yield first + 2;
}
let i = createIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.next(10)); // {value: 12, done: false}

2、在迭代器中拋出錯誤

function *createIterator() {
  let first = yield 1;
  yield first + 2;
}
let i = createIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.throw(new Error("error"))); // error
console.log(i.next()); //不再執(zhí)行

3、生成器返回語句

生成器中添加return表示退出操作。
function *createIterator() {
let first = yield 1;
return;
yield first + 2;
}
let i = createIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.next()); // {value: undefined, done: true}

4、委托生成器

生成器嵌套生成器

function *aIterator() {
  yield 1;
}
function *bIterator() {
  yield 2;
}
function *cIterator() {
  yield *aIterator()
  yield *bIterator()
}

let i = cIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.next()); // {value: 2, done: false}
異步任務(wù)執(zhí)行器

ES6之前,我們使用異步的操作方式是調(diào)用函數(shù)并執(zhí)行回調(diào)函數(shù)。

書上舉的例子挺好的,在nodejs中,有一個讀取文件的操作,使用的就是回調(diào)函數(shù)的方式。

var fs = require("fs");
fs.readFile("xx.json", function(err, contents) {
  //在回調(diào)函數(shù)中做一些事情
})

那么任務(wù)執(zhí)行器是什么呢?

任務(wù)執(zhí)行器是一個函數(shù),用來循環(huán)執(zhí)行生成器,因為我們知道生成器需要執(zhí)行N次next()方法,才能運行完,所以我們需要一個自動任務(wù)執(zhí)行器幫我們做這些事情,這就是任務(wù)執(zhí)行器的作用。

下面我們編寫一個異步任務(wù)執(zhí)行器。

//taskDef是一個生成器函數(shù),run是異步任務(wù)執(zhí)行器
function run(taskDef) {
  let task = taskDef(); //調(diào)用生成器
  let result = task.next(); //執(zhí)行生成器的第一個next(),返回result
  function step() {
    if(!result.done) {
    //如果done為false,則繼續(xù)執(zhí)行next(),并且循環(huán)step,直到done為true退出。
      result = task.next(result.value);
      step();
    }
  }
  step(); //開始執(zhí)行step()
}

測試一下我們編寫的run方法,我們不再需要console.log N個next了,因為run執(zhí)行器已經(jīng)幫我們做了循環(huán)執(zhí)行操作:

run(function *() {
  let value = yield 1;
  value = yield value + 20;
  console.log(value) // 21
})
總結(jié)

本章講了3個概念,迭代器、生成器、任務(wù)執(zhí)行器。

迭代器是一個對象。

生成器是一個函數(shù),它最終返回迭代器。

任務(wù)執(zhí)行器一個函數(shù)(或者也叫生成器的回調(diào)函數(shù)),幫我們自動執(zhí)行生成器的內(nèi)部運算,最終返回迭代器。

不知道看到這里,你明白3者的區(qū)別和用法沒?

=> 返回文章列表

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

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

相關(guān)文章

  • ES6Iterator&Generator

    摘要:可迭代對象就具有屬性,它是一種與迭代器密切相關(guān)的對象。它通過指定的函數(shù)可以返回一個作用于附屬對象的迭代器。迭代器特點每次調(diào)用方法時,返回一個數(shù)組,數(shù)組中兩個元素,分別表示鍵和值。示例之輸出輸出輸出之迭代器特點返回集合中存在的每一個鍵。 Iterator由來 不推薦Iterator方法。 Iterator 函數(shù)是一個 SpiderMonkey 專有特性,并且會在某一時刻被刪除。有一點,需...

    xietao3 評論0 收藏0
  • 【重溫基礎(chǔ)】13.迭代生成

    摘要:迭代器和生成器將迭代的概念直接帶入核心語言,并提供一種機(jī)制來自定義循環(huán)的行為。本文主要會介紹中新增的迭代器和生成器。屬性本身是函數(shù),是當(dāng)前數(shù)據(jù)結(jié)構(gòu)默認(rèn)的迭代器生成函數(shù)。 本文是 重溫基礎(chǔ) 系列文章的第十三篇。今日感受:每次自我年終總結(jié),都會有各種情緒和收獲。 系列目錄: 【復(fù)習(xí)資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎(chǔ)】1.語法和數(shù)據(jù)類型 【重溫基礎(chǔ)】2.流...

    ymyang 評論0 收藏0
  • 深入理解ES6筆記——導(dǎo)讀

    摘要:最近買了深入理解的書籍來看,為什么學(xué)習(xí)這么久還要買這本書呢主要是看到核心團(tuán)隊成員及的創(chuàng)造者為本書做了序,作為一個粉絲,還是挺看好這本書能給我?guī)硪粋€新的升華,而且本書的作者也非常厲害。 使用ES6開發(fā)已經(jīng)有1年多了,以前看的是阮一峰老師的ES6教程,也看過MDN文檔的ES6語法介紹。 最近買了《深入理解ES6》的書籍來看,為什么學(xué)習(xí)ES6這么久還要買這本書呢?主要是看到Daniel A...

    Godtoy 評論0 收藏0

發(fā)表評論

0條評論

AndroidTraveler

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<