偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

遍歷得到數(shù)組 Or Iterator 遍歷器?

開發(fā) 前端
熟悉 ES 語法數(shù)據(jù)結(jié)構(gòu)的朋友一定很清楚,原生對象數(shù)據(jù)結(jié)構(gòu)并不支持 obj.keys()、obj.values()和 obj.entries() 方法,數(shù)組與 map、set 等數(shù)據(jù)結(jié)構(gòu)才支持。但仍可以通過 Object.keys(obj)、Object.values(obj)、Object.entries(obj)獲取原生對象中可遍歷的屬性組成數(shù)組類型數(shù)據(jù)結(jié)構(gòu)。

[[433429]]

一、背景

故事的開頭是這樣的...

在遍歷數(shù)組與對象屬性時,對使用 obj.keys()、obj.values()和 obj.entries() 還是 Object.keys(obj)、Object.values(obj)、Object.entries(obj)方法產(chǎn)生了一些困惑。話不多說,先放問題:

需求:想要遍歷一個對象,并獲取遍歷對象的屬性值 實(shí)現(xiàn):Object.keys()、Object.values() 和 Object.entries() 方法 問題:一不小心同數(shù)組的 entries(),keys()和 values() 方法混淆了~QAQ

二、keys()、values()、entries()遍歷方法

熟悉 ES 語法數(shù)據(jù)結(jié)構(gòu)的朋友一定很清楚,原生對象數(shù)據(jù)結(jié)構(gòu)并不支持 obj.keys()、obj.values()和 obj.entries() 方法,數(shù)組與 map、set 等數(shù)據(jù)結(jié)構(gòu)才支持。但仍可以通過 Object.keys(obj)、Object.values(obj)、Object.entries(obj)獲取原生對象中可遍歷的屬性組成數(shù)組類型數(shù)據(jù)結(jié)構(gòu)。

也就是說,keys()、values()和 entries() 方法有兩種:

ES5-ES2017 相繼引入 Object.keys 、Object.values 和 Object.entries 方法,返回一個數(shù)組,成員是參數(shù)對象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名/鍵值/鍵值對,可以用 for...of 循環(huán)進(jìn)行遍歷;

ES6 提供 entries(),keys() 和 values() -- 可用于遍歷數(shù)組/Map/Set 等類數(shù)組數(shù)據(jù)結(jié)構(gòu)實(shí)例,返回一個(Iterator)遍歷器對象,可以用 for...of 循環(huán)進(jìn)行遍歷。

注意這里又有兩點(diǎn)區(qū)別:

兩者調(diào)用語法不同,顯而易見;

前者返回的是一個可迭代的對象,而后者返回的是一個真正的數(shù)組。

有沒有被繞暈?那我們先來看第一個問題吧 -- 調(diào)用語法的不同

Q1: Object.keys 、Object.values 和 Object.entries 方法

為了區(qū)分這兩種調(diào)用語法,我們必須得來回顧下原型鏈的相關(guān)知識。

因?yàn)檫@里的 entries(),keys()和 values() 方法正是是調(diào)用原型對象構(gòu)造函數(shù)上的方法。如下圖可以看到,對于一個普通對象,這三個方法在 Object 對象的[[prototype]]下的 constructor 中:

而對于一個數(shù)組結(jié)構(gòu)來說,這三個方法可以在數(shù)組原型鏈中和原型鏈上層對象原型的 constructor 中同時找到:

即 Object.keys(arr)調(diào)用的是數(shù)組原型鏈頂層原型對象 constructor 的方法,而數(shù)組本身也支持的 arr.keys()方法,則是調(diào)用數(shù)組原型鏈上的方法。

即對象只支持前種調(diào)用方式,而數(shù)組同時支持這兩種調(diào)用:

同時我們知道在 JavaScript 中,對象是所有復(fù)雜結(jié)構(gòu)的基礎(chǔ)。也正對應(yīng)了其他復(fù)雜結(jié)構(gòu)原型鏈的頂端是對象原型結(jié)構(gòu)?,F(xiàn)在應(yīng)該能夠知道為何普通對象不支持 obj.keys()、obj.values()和 obj.entries() 方法了,但到這里就不得不提出另一個疑問了:

Q2: 如何讓一個對象支持 obj.keys()、obj.values()和 obj.entries() 方法呢?

理論上,我們是可以為一個對象構(gòu)造任意方法,那么如何實(shí)現(xiàn)和數(shù)組一樣的遍歷方法呢?本質(zhì)上這個方法是能夠生成一個遍歷器。

  1. let objE = { 
  2.   data: [ 'hello''world' ], 
  3.   keys: function() { 
  4.     const self = this; 
  5.     return { 
  6.       [Symbol.iterator]() { 
  7.         let index = 0; 
  8.         return { 
  9.           next() { 
  10.             if (index < self.data.length) { 
  11.               return { 
  12.                 value: self.data[index++], 
  13.                 done: false 
  14.               }; 
  15.             } 
  16.             return { value: undefined, done: true }; 
  17.           } 
  18.         }; 
  19.       } 
  20.     } 
  21.   } 
  22. }; 

上述,我們自己創(chuàng)建了一個 data 對象,并實(shí)現(xiàn)了它自己的 data.values() 方法。同時,我們依然可以對它調(diào)用 Object.values(data) 方法。

從上面的方法不難看出,我們在對象中通過添加 Symbol.iterator 手動構(gòu)造了一個輸出遍歷器函數(shù),關(guān)于遍歷器的討論我們在下一節(jié)討論,現(xiàn)在先來討論調(diào)用返回結(jié)果的區(qū)別。

Q3: 兩種調(diào)用方法返回結(jié)果:遍歷器與數(shù)組

1)第一種調(diào)用方法,根據(jù)定義可知:返回一個數(shù)組,數(shù)組成員是參數(shù)對象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名/鍵值/鍵值對。

敲重點(diǎn)!!!這三個方法只返回對象自身的可遍歷屬性,即屬性描述對象的 enumerable 為 true。

我們可以通過 for ... in 循環(huán)來實(shí)現(xiàn)相同的遍歷效果。

2)而第二種方法,返回一個遍歷器:顧名思義,遍歷器也可以滿足循環(huán)遍歷的需求。

本質(zhì)上,遍歷器的定義是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機(jī)制。接下來就來了解下適用于不同數(shù)據(jù)結(jié)構(gòu)的遍歷器。

三、Iterator 遍歷器

首先我們知道,目前主要有四種表示“集合”的數(shù)據(jù)結(jié)構(gòu):數(shù)組(Array)、對象(Object)、Map 和 Set,這里表示"集合"的對象例如 NodeList 集合類數(shù)組對象,而遍歷器可以使我們遍歷訪問這些集合。

實(shí)際上,原生具備 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)包括 Array、Map、Set、String、TypedArray、函數(shù)的 arguments 對象和 NodeList 對象。

具體遍歷器的概念可參考阮一峰老師 ES6 入門 Iterator 一章,已經(jīng)十分詳細(xì)清楚:

因此,Iterator 遍歷器本質(zhì)上為所有數(shù)據(jù)結(jié)構(gòu),提供了一種統(tǒng)一的訪問機(jī)制,即 for...of 循環(huán)。

關(guān)于遍歷,我們前面已經(jīng)講到了遍歷對象屬性,這里再提一嘴:

1. 遍歷類數(shù)組對象/Array/Map/Set 等數(shù)組數(shù)據(jù)結(jié)構(gòu)實(shí)例

當(dāng)使用 for...of 循環(huán)遍歷某種數(shù)據(jù)結(jié)構(gòu)時,該循環(huán)會自動去尋找 Iterator 接口。一種數(shù)據(jù)結(jié)構(gòu)只要部署了 Iterator 接口,我們就稱這種數(shù)據(jù)結(jié)構(gòu)是“可遍歷的”(iterable)。ES6 規(guī)定,默認(rèn)的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的 Symbol.iterator 屬性,換句話說,一個數(shù)據(jù)結(jié)構(gòu)只要具有 Symbol.iterator 屬性,就可以認(rèn)為是“可迭代/遍歷的”(iterable)。

2. 獲取對象可遍歷屬性

Object.keys 、Object.values 和 Object.entries 方法只返回對象自身的可遍歷屬性,通過屬性描述對象的 enumerable 標(biāo)識改對象屬性是否可以遍歷。同時因?yàn)槠胀▽ο?not iterable,即普通對象不具有 Symbol.iterator 屬性,所以無法通過 for...of 循環(huán)直接遍歷,否則會報(bào)錯 Uncaught TypeError: obj is not iterable。

可見,數(shù)組及類數(shù)組的遍歷(迭代)與普通對象中的提到的遍歷是不同的,這分別取決于各自的 iterable 和 enumerable 屬性。

3. for ... of

ES6 中引入 for...of 循環(huán),很多時候用以替代 for...in 和 forEach() ,并支持新的迭代協(xié)議。for...of 語句在可迭代對象上創(chuàng)建一個迭代循環(huán),調(diào)用自定義迭代鉤子,并為每個不同屬性的值執(zhí)行語句。

那么終極問題:如何實(shí)現(xiàn) Symbol.iterator 方法,使普通對象可被 for of 迭代?其實(shí)在 Q2 部分已經(jīng)實(shí)現(xiàn)了。

嘗試給普通對象實(shí)現(xiàn)一個 Symbol.iterator 接口:

  1. // 普通對象 
  2. const obj = { 
  3.   foo: 'value1'
  4.   bar: 'value2'
  5.   [Symbol.iterator]() { 
  6.     // 這里 Object.keys 不會獲取到 Symbol.iterator 屬性 
  7.     const keys = Object.keys(obj); // 得到一個數(shù)組 
  8.     let index = 0; 
  9.     return { 
  10.       next: () => { 
  11.         if (index < keys.length) { 
  12.           // 迭代結(jié)果 未結(jié)束 
  13.           return { 
  14.             value: this[keys[index++]], 
  15.             done: false 
  16.           }; 
  17.         } else { 
  18.           // 迭代結(jié)果 結(jié)束 
  19.           return { value: undefined, done: true }; 
  20.         } 
  21.       } 
  22.     }; 
  23.   } 
  24. for (const value of obj) { 
  25.   console.log(value); // value1 value2 
  26. }; 

for...of 循環(huán)內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的 Symbol.iterator 方法,for...of 循環(huán)可以使用的范圍包括數(shù)組、Set 和 Map 結(jié)構(gòu)、某些類似數(shù)組的對象(比如 arguments 對象、DOM NodeList 對象)、后文的 Generator 對象,以及字符串。

for...of 循環(huán)作為 ES6 新引入的一種循環(huán),具有以下明顯優(yōu)勢(按需使用):

有著同 for...in 一樣的簡潔語法,但是沒有 for...in 那些缺點(diǎn)(無序,不適用于遍歷數(shù)組)。

不同于 forEach 方法,它可以與 break、continue 和 return 配合使用。

提供了遍歷所有數(shù)據(jù)結(jié)構(gòu)的統(tǒng)一操作接口。

以上是我從 keys()、values()、entries() 遍歷方法出發(fā)對遍歷器產(chǎn)生的幾點(diǎn)思考,如有不足之處,歡迎指正~~~

 

責(zé)任編輯:武曉燕 來源: 微醫(yī)大前端技術(shù)
相關(guān)推薦

2009-11-17 15:07:16

PHP數(shù)組遍歷

2009-11-16 16:23:10

PHP數(shù)組遍歷

2021-03-29 12:01:00

遍歷數(shù)組for循環(huán)

2019-07-25 10:08:05

JavaScript數(shù)組轉(zhuǎn)換

2025-08-06 06:10:00

JavaScrip數(shù)組for 循環(huán)

2009-09-08 09:59:26

LINQ遍歷多個數(shù)組

2024-04-25 07:54:46

遍歷數(shù)組PythonFor循環(huán)

2009-11-17 15:00:19

PHP遍歷數(shù)組

2022-09-07 11:52:48

forforEach前端

2023-11-07 10:10:36

設(shè)計(jì)模式元素

2020-06-30 10:37:55

JavaScript開發(fā)技術(shù)

2021-06-18 10:05:14

JavaScript數(shù)組遍歷

2021-02-05 23:08:10

JS代碼循環(huán)

2021-06-15 10:01:27

JavaScript數(shù)組遍歷Entries

2021-01-11 07:51:16

DOM對象節(jié)點(diǎn)樹

2021-08-02 10:01:09

Iterator接口Java項(xiàng)目開發(fā)

2009-09-16 17:21:53

LINQ遍歷

2022-10-26 09:27:59

Python編程迭代器協(xié)議

2021-07-22 07:20:24

JS 遍歷方法前端

2018-04-28 19:01:54

JavaScript數(shù)組Promise
點(diǎn)贊
收藏

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