自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從理解到實(shí)現(xiàn)輕松掌握 ES6 中的迭代器

開(kāi)發(fā) 前端
JavaScript 中除了 Array 之外,ES6 還新增加了 Map、Set 結(jié)構(gòu),當(dāng)我們需要操作這些數(shù)據(jù)時(shí),就需要一種統(tǒng)一的接口來(lái)處理這些不同的數(shù)據(jù)結(jié)構(gòu)。ES6 中新增加的 Iterator(迭代器)就提供了這樣一種機(jī)制。

[[352311]]

JavaScript 中除了 Array 之外,ES6 還新增加了 Map、Set 結(jié)構(gòu),當(dāng)我們需要操作這些數(shù)據(jù)時(shí),就需要一種統(tǒng)一的接口來(lái)處理這些不同的數(shù)據(jù)結(jié)構(gòu)。ES6 中新增加的 Iterator(迭代器)就提供了這樣一種機(jī)制。

Symbol.iterator 支持的數(shù)據(jù)結(jié)構(gòu)

ES6 中提供了 Symbol.iterator 方法,該方法返回一個(gè)迭代器對(duì)象,目前 Array、Set、Map 這些數(shù)據(jù)結(jié)構(gòu)默認(rèn)具有 Symbol.iterator 屬性,如下所示,可以看到 Object 類型是沒(méi)有的。

  1. console.log([][Symbol.iterator]()); // Object [Array Iterator] {} 
  2. console.log((new Map())[Symbol.iterator]()); // [Map Entries] {  } 
  3. console.log((new Set())[Symbol.iterator]()); // [Set Iterator] {  } 
  4. console.log({}[Symbol.iterator]); // undefined 

除了上面提到這些數(shù)據(jù)結(jié)構(gòu),JavaScript 中一些類似數(shù)組的對(duì)象也默認(rèn)具有 Symbol.iterator 屬性,例如:字符串、arguments 對(duì)象、DOM 的 NodeList 對(duì)象。

  • 字符串
  1. const str = 'nodejs'
  2. console.log(str[Symbol.iterator]()); // Object [String Iterator] {} 
  3.  
  4. for (const val of str) { 
  5.   console.log(val); // n o d e j s 
  • arguments 對(duì)象
  1. function print() { 
  2.   console.log(arguments[Symbol.iterator]()); // Object [Array Iterator] {} 
  3.   for (const val of arguments) { 
  4.     console.log(val); // n o d e 
  5.   } 
  6. print('n''o''d''e'
  • DOM NodeList 對(duì)象
  1. const divNodeList = document.getElementsByTagName('div'
  2. console.log(divNodeList[Symbol.iterator]()) // Array Iterator {} 
  3. for (const div of divNodeList) { 
  4.  // 會(huì)輸出每個(gè) div 標(biāo)簽 
  5.  console.log(div); 

迭代器對(duì)象的 next 方法

調(diào)用可迭代對(duì)象的 Symbol.iterator 方法會(huì)返回一個(gè)迭代器對(duì)象,它的接口中有一個(gè) next 方法,該方法返回 value 和 done 兩個(gè)屬性,其中 value 屬性是當(dāng)前成員的值,done 屬性表示遍歷是否結(jié)束。了解生成器函數(shù)(Generator)的可能不會(huì)陌生,同樣的當(dāng)你執(zhí)行一個(gè)生成器函數(shù)也會(huì)得到一個(gè)迭代器對(duì)象,但是要區(qū)分 生成器和迭代器不是一個(gè)概念。

  1. const arr = ['N''o''d''e']; 
  2. const iterator = arr[Symbol.iterator](); 
  3.  
  4. console.log(iterator.next()); // { value: 'N', done: false } 
  5. console.log(iterator.next()); // { value: 'o', done: false } 
  6. console.log(iterator.next()); // { value: 'd', done: false } 
  7. console.log(iterator.next()); // { value: 'e', done: false } 
  8. console.log(iterator.next()); // { value: undefined, done: true } 

上例中聲明一個(gè)數(shù)組 arr,調(diào)用 arr 的 Symbol.iterator 方法創(chuàng)建了一個(gè)迭代器對(duì)象 iterator 之后不斷調(diào)用 next 方法返回當(dāng)前數(shù)組內(nèi)容,直到 next 方法返回值 done 為 true 則該數(shù)組訪問(wèn)完畢。

Iterator 接口遍歷

解構(gòu)賦值

數(shù)組、Set、Map 解構(gòu)賦值時(shí),會(huì)默認(rèn)調(diào)用 Symbol.iterator 方法。注意 Map 調(diào)用 Symbol.iterator 方法返回的是一個(gè) entries 方法,該方法返回的是一個(gè)新的迭代器對(duì)象且按插入順序包含了 Map 對(duì)象中每個(gè)元素的 [key, value] 數(shù)組,所以調(diào)用 Map 實(shí)例的 keys 或 values 方法也會(huì)返回一個(gè)新的迭代器對(duì)象。

  1. const set = new Set().add('n').add('o'); 
  2. const map = new Map().set('d').set('e'); 
  3. const [xSet, ySet] = set
  4. console.log(xSet, ySet) // n o 
  5. const [xMap, yMap] = map.keys(); 
  6. console.log(xMap, yMap) // d e 

擴(kuò)展運(yùn)算符

ES6 中的擴(kuò)展運(yùn)算符(...)也會(huì)默認(rèn)調(diào)用數(shù)組、Set、Map 等結(jié)構(gòu)的 Symbol.iterator 方法。

  1. const set = new Set('node'); 
  2. const [x, y, ...z] = set
  3. console.log(x, y, z); // n o [ 'd''e' ] 

for...of 循環(huán)

ES6 借鑒了 C++、Python 等語(yǔ)言引入了 for...of 循環(huán),該循環(huán)內(nèi)部也會(huì)調(diào)用 Symbol.iterator 方法,只要具有 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)都可以使用。

  1. const set = new Set().add('n').add('o'); 
  2.  
  3. for (const val of set) { 
  4.   console.log(val); 

for...of 循環(huán)在執(zhí)行中還可以使用 break; 中斷迭代器的執(zhí)行。以下示例,修改循環(huán)語(yǔ)句在執(zhí)行第一次 val 等于 n 之后執(zhí)行 break。

  1. for (const val of set) { 
  2.   console.log(val); // n 
  3.   if (val === 'n') break; 

其它方法

數(shù)組默認(rèn)是支持 Iterator 接口,所以任何接收數(shù)組做為參數(shù)的方法也都會(huì)默認(rèn)調(diào)用 Symbol.iterator 方法,如下所示:

  1. const set = new Set().add('n').add('o'); 
  2. console.log(Array.from(set)); // [ 'n''o' ] 
  3. Promise.all(set).then(val => console.log(val)) // [ 'n''o' ] 
  4. Promise.race(set).then(val => console.log(val)) // n 

自定義迭代器

迭代協(xié)議

  • 參照可迭代協(xié)議,要成為可迭代對(duì)象首先要有一個(gè) **@@iterator **即(Symbol.iterator)屬性,該屬性為一個(gè)無(wú)參數(shù)的函數(shù),返回一個(gè)符合迭代器協(xié)議的對(duì)象。
  • 根據(jù)迭代器協(xié)議定義這個(gè)迭代器對(duì)象要返回一個(gè) next() 方法,這個(gè) next() 方法返回一個(gè)包含 value、done 屬性的對(duì)象。
  1. const  myIterator = { 
  2.   // for...of 循環(huán)會(huì)用到 
  3.   [Symbol.iterator]: function() { return this }, 
  4.    
  5.   // 標(biāo)準(zhǔn)的迭代器接口方法 
  6.   nextfunction() { 
  7.    // ... 
  8.   } 

如果用 TypeScript 寫(xiě)法描述如下:

  1. // 遍歷器接口 Iterable 
  2. interface Iterable { 
  3.  [Symbol.iterator]: Iterator 
  4.  
  5. // 迭代器對(duì)象 
  6. interface Iterator { 
  7.  next(value?: any): IterationResult, 
  8.  
  9. // next 方法返回值定義 
  10. interface IterationResult { 
  11.  value: any
  12.   done: boolean 

基于普通函數(shù)的迭代器實(shí)現(xiàn)

迭代器的函數(shù)實(shí)現(xiàn)可以是一個(gè)普通函數(shù)也可以是一個(gè)生成器函數(shù),我們先以普通函數(shù)為例,定義一個(gè) Range 構(gòu)造函數(shù),用來(lái)輸出兩個(gè)數(shù)值區(qū)域的所有值。

  1. function Range(start, end) { 
  2.   this.id = start; 
  3.   this.end = end
  4. Range.prototype[Symbol.iterator] = function() { return this } 
  5. Range.prototype.next = function next() { 
  6.   if (this.id > this.end) { 
  7.     return { value: undefined, done: true } 
  8.   } 
  9.  
  10.   return { value: this.id++, done: false } 
  11. const r1 = new Range(0, 3); 
  12. const it = r1[Symbol.iterator]() 
  13. for (const id of r1) { 
  14.   console.log(id); // 0,1,2,3 

基于生成器函數(shù)的迭代器實(shí)現(xiàn)

使用生成器函數(shù)(Generator)實(shí)現(xiàn)是最簡(jiǎn)單的,只要使用 yield 語(yǔ)句返回每一次的值即可。如下所示:

  1. Range.prototype[Symbol.iterator] = function* () { 
  2.   while (this.id <= this.end) { 
  3.     yield this.id++; 
  4.   } 

異步迭代器

到目前為止我們上面講解的都是同步模式的迭代器,這個(gè)很好理解,因?yàn)槲覀兊臄?shù)據(jù)源本身也就是同步的,但是在 Node.js 中一次網(wǎng)絡(luò) I/O 請(qǐng)求或者一次文件 I/O 請(qǐng)求,它們都是基于事件是異步的,所以我們就不能像使用 Symbol.iterator 的方式來(lái)使用。ECMAScript 2018 標(biāo)準(zhǔn)中提供了 **Symbol.asyncIterator **屬性,這是一個(gè)異步迭代器,如果一個(gè)對(duì)象設(shè)置了該屬性,它就是異步可迭代對(duì)象,相應(yīng)的我們要使用 for await...of 循環(huán)遍歷數(shù)據(jù)。

自定義異步迭代器

  1. function Range(start, end) { 
  2.   this.id = start; 
  3.   this.end = end
  4. // 與上面不同,function 前我們?cè)黾恿?nbsp;async 關(guān)鍵字 
  5. Range.prototype[Symbol.asyncIterator] = async function* () { 
  6.   while (this.id <= this.end) { 
  7.     yield this.id++; 
  8.   } 
  9. const r1 = new Range(0, 3); 
  10. console.log(r1[Symbol.asyncIterator]()); // Object [AsyncGenerator] {} 
  11. for await (const id of r1) { 
  12.   console.log(id); // 0,1,2,3 

與同步迭代器的不同

  • 同步迭代器返回的是一個(gè)常規(guī)的 { value, done } 對(duì)象,而異步迭代器返回的是一個(gè)包含 { value, done } 的 Promise 對(duì)象。
  • 同步可迭代協(xié)議具有 Symbol.iterator 屬性,異步可迭代協(xié)議具有 Symbol.asyncIterator 屬性。
  • 同步迭代器使用 for...of 循環(huán)遍歷,異步迭代器使用 for await...of 循環(huán)遍歷。

異步迭代器的支持目前沒(méi)有默認(rèn)設(shè)定了 [Symbol.asyncIterator] 屬性的 JavaScript 內(nèi)建的對(duì)象。不過(guò),WHATWG(網(wǎng)頁(yè)超文本應(yīng)用技術(shù)工作小組)Streams 會(huì)被設(shè)定為第一批異步可迭代對(duì)象,[Symbol.asyncIterator] 最近已在設(shè)計(jì)規(guī)范中落地。

下一節(jié)我們將會(huì)講解異步迭代器在 Node.js 中的使用,歡迎關(guān)注。

Reference

[1]你不知道的JavaScript(中卷): https://book.douban.com/subject/26854244/[2]可迭代協(xié)議: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols[3]Symbol.asyncIterator: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator

本文轉(zhuǎn)載自微信公眾號(hào)「Nodejs技術(shù)?!?,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Nodejs技術(shù)棧公眾號(hào)。 

 

責(zé)任編輯:武曉燕 來(lái)源: Nodejs技術(shù)棧
相關(guān)推薦

2018-07-16 16:10:03

前端JavaScript面向?qū)ο?/a>

2024-08-05 00:00:50

ES6JavaScriptClass

2011-05-20 17:10:31

Bing云計(jì)算

2022-09-14 08:01:36

JoinMySQL迭代器

2023-05-10 08:21:42

Es6Set

2023-03-01 00:07:32

JavaScript迭代器生成器

2022-06-01 09:06:58

ES6數(shù)組函數(shù)

2021-08-16 07:05:58

ES6Promise開(kāi)發(fā)語(yǔ)言

2017-08-31 14:25:34

前端JavascriptES6

2020-07-01 07:58:20

ES6JavaScript開(kāi)發(fā)

2022-10-31 16:20:33

JavaScript前端開(kāi)發(fā)

2024-06-26 08:18:08

ES6模板字符串

2023-11-23 10:21:11

ECMAScriptJavaScript

2021-07-30 07:10:07

ES6函數(shù)參數(shù)

2021-07-16 07:26:48

ES6javascript開(kāi)發(fā)語(yǔ)言

2022-07-26 09:02:15

ES6ES13ECMAScript

2018-05-28 09:20:10

Python迭代for循環(huán)

2023-03-01 15:39:50

JavaScrip對(duì)象屬性ES6

2023-05-28 23:49:38

JavaScrip開(kāi)發(fā)

2017-10-09 18:21:20

JavaScriptES6ES8
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)