摸魚日記之—— js 中的遍歷器:Iterator 與 for of

来源:https://www.cnblogs.com/jandr/archive/2020/06/09/13066953.html
-Advertisement-
Play Games

1.什麼是Iterator ? 遍歷器(Iterator)它是一種介面,為各種不同的數據結構提供統一的訪問機制。任何數據結構只要部署 Iterator 介面,就可以完成遍歷操作。 Iterator 的作用有三個: 1.是為各種數據結構,提供一個統一的、簡便的訪問介面; 2.是使得數據結構的成員能夠按 ...


 1.什麼是Iterator ?


 遍歷器(Iterator)它是一種介面,為各種不同的數據結構提供統一的訪問機制。任何數據結構只要部署 Iterator 介面,就可以完成遍歷操作。

Iterator 的作用有三個:

1.是為各種數據結構,提供一個統一的、簡便的訪問介面;

2.是使得數據結構的成員能夠按某種次序排列;

3.是 ES6 創造了一種新的遍歷命令for...of迴圈,Iterator 介面主要供for...of消費。

 

2.Iterator怎麼用 ?


for...of語句可迭代對象(包括 ArrayMapSetStringTypedArray,arguments 對象等等)上創建一個迭代迴圈,調用自定義迭代鉤子,併為每個不同屬性的值執行語句

 

/**
 * 語法
 * @variable 每次迭代中屬性的值
 * @iterable 被迭代枚舉其屬性的對象
 */
for (variable of iterable) {
    //statements
}

const array1 = ['a', 'b', 'c']; for (const element of array1) { console.log(element); } // a // b // c


 

接下來一起來實踐一下上面那些類型是不是真的可以用

// Array
let arr = [10, 20, 30];

for (let value of arr) {
    value += 1;
    console.log(value);
}
// 11
// 21
// 31

// Map
let map = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (let entry of map) {
  console.log(entry);
}
// ["a", 1]
// ["b", 2]
// ["c", 3]

// Set
let set = new Set([1, 1, 2, 2, 3, 3]);

for (let value of set) {
  console.log(value);
}
// 1
// 2
// 3

// String
let str = "boo";

for (let value of str) {
  console.log(value);
}
// "b"
// "o"
// "o"

// TypedArray
let typedArr = new Uint8Array([0x00, 0xff]);

for (let value of typedArr) {
  console.log(value);
}
// 0
// 255

// arguments
(function() {
  for (let argument of arguments) {
    console.log(argument);
  }
})(1, 2, 3);
// 1
// 2
// 3
View Code

 

那其他的類型用for of會怎麼樣?

比如一個普通的object類型

 

產品:“那我就要把for of用在對象上”

我:“對象不能用for of,你看這不都報錯了嘛”

產品:“不聽不聽,你是不是不想做”

我:“好吧好吧,既然你想要用,那就滿足你”

 

首先要瞭解遍歷器 Iterator 的協議,傳送門:MDN 迭代協議

簡而言之就是:

迭代協議具體分為兩個協議:可迭代協議迭代器協議

可迭代協議:

可迭代協議允許 JavaScript 對象定義或定製它們的迭代行為,例如,在一個 for..of 結構中,哪些值可以被遍歷到。一些內置類型同時是內置可迭代對象,並且有預設的迭代行為,比如 Array 或者 Map,而其他內置類型則不是(比如 Object))。

要成為可迭代對象, 一個對象必須實現 @@iterator 方法。這意味著對象(或者它原型鏈上的某個對象)必須有一個鍵為 @@iterator 的屬性,可通過常量 Symbol.iterator 訪問該屬性:

 

迭代器協議:

迭代器協議定義了產生一系列值(無論是有限個還是無限個)的標準方式。當值為有限個時,所有的值都被迭代完畢後,則會返回一個預設返回值。

只有實現了一個擁有以下語義(semantic)的 next() 方法,一個對象才能成為迭代器:

 

var obj = {
  data: [1,2,3],
  [Symbol.iterator]() {
    var nextIndex = 0, self = this;
    return {
      next() {
        var done = nextIndex >= self.data.length;
        var value = done ? undefined : self.data[nextIndex++]
        return { value: value, done: done }
      }
    }
  }
}


for (const item of obj) { console.log(item) }
// 1
// 2
// 3

 

 由此可見,普通對象不可直接使用for of,在[Symbol.iterator]屬性上部署遍歷器生成的方法後即可被for of使用(原型鏈上的對象具有該方法也可)

實際上,對象之所以沒有預設部署 Iterator 介面,是因為對象的哪個屬性先遍歷,哪個屬性後遍歷是不確定的,需要開發者手動指定。

那知道了上面遍歷器的協議,我們可以通過更簡單的方式判定上述六種類型是否實現了遍歷器介面了

Array.prototype.hasOwnProperty(Symbol.iterator);
// true
Set.prototype.hasOwnProperty(Symbol.iterator);
// true
Map.prototype.hasOwnProperty(Symbol.iterator);
// true
String.prototype.hasOwnProperty(Symbol.iterator);
// true
(function(){ console.log(arguments.hasOwnProperty(Symbol.iterator)) })(1,2,3)
// true
Uint8Array.prototype.__proto__.hasOwnProperty(Symbol.iterator)
// true

 

 

3. 與for in的區別


可能看到for of 有人想到for in,那這兩個長這麼像,他兩有啥區別呢。咱們一起來看看

var arr1 = ['a', 'b', 'c', 'd'];
// 輸出鍵名
for (let a in arr1) {
  console.log(a); // 0 1 2 3
}

// 輸出鍵值
for (let a of arr1) { console.log(a); // a b c d }

// 註意:還有個細節
// for...of迴圈調用遍歷器介面,數組的遍歷器介面只返回具有數字索引的屬性。這一點跟for...in迴圈也不一樣。
let arr2 = [3, 5, 7];
arr2.foo = 'hello';

for (let i in arr2) {
  console.log(i); // "0", "1", "2", "foo"
}

for (let i of arr2) {
  console.log(i); //  "3", "5", "7"
}

 

4. 與其他迴圈的區別


 

var arr = Array(10).fill(1);
// for i 迴圈法,不夠簡潔
for (var i = 0; i < arr.length; i++) {
  console.log(arr[i])
}

// forEach 迴圈,不能手動跳出迴圈
arr.forEach(function (value) {
  console.log(value);
})

// for i 迴圈獲取的是鍵名,而不是鍵值,因此不大適用於遍曆數組
for (var i in arr) {
  console.log(i)
}
// for of 可以跳出迴圈,語法簡潔
for (var i of arr) {
  console.log(i)
}

經比較,遍歷對象用for in, 遍曆數組用for of 

 

實際上,要實現對象的Iterator介面還有更簡潔的方法,就是使用generator

let obj = {
  * [Symbol.iterator]() {
    yield 'hello';
    yield 'world';
  }
};

for (let x of obj) {
  console.log(x);
}
// hello
// world

看到這裡有人又奇怪了,這個 * 號是個什麼鬼?

答案是 Generator 函數,Generator 函數是一個普通函數,但是有兩個特征。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield表達式,定義不同的內部狀態(yield在英語里的意思就是“產出”)。

詳情請戳這裡

2020-06-09 11:23:51


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、前言、web標準 1. 瀏覽器內核 瀏覽器 內核 備註 IE Trident IE、獵豹瀏覽器、360瀏覽器、百度瀏覽器 Firefox Gecko 可惜這幾年已經沒落了,打開速度慢,升級平凡、豬一樣的隊友Flash Safari webkit 現在很多人錯誤把webkit叫做Chrome內核( ...
  • 表單form 作用:用於獲取用戶輸入的信息,並且將信息提交到伺服器 學習表單就是學習表單中有哪些控制項.比如:文本域(textarea)、下拉列表、單選框(radio-buttons)、覆選框(vheckboxes)等等。 表單通常使用表單標簽<from>來設置: <form> <input /> < ...
  • 2020-05-26 Nodejs v12.17.0 LTS 版發佈,去掉 --experimental-modules 標誌。 1、雖然已在最新的 LTS v12.17.0 中支持,但是目前仍處於 Stability: 1 - Experimental 實驗階段,如果是在生產環境使用該功能,還應保 ...
  • 寫在前面 1.每一篇文章都希望您有所收穫,每一篇文章都希望您能靜下心來瀏覽、閱讀。每一篇文章都是作者精心打磨的作品。 2.如果您覺得二郎神楊戩有點東西的話,作者希望你可以幫我點亮那個點贊的按鈕,對於二郎神楊戩這個暖男來說,真的真的非常重要,這將是我持續寫作的動力。您只需要小手輕輕一點,帶來的卻是溫暖 ...
  • 前言 本文是我在閱讀 Koa 源碼後,並實現迷你版 Koa 的過程。如果你使用過 Koa 但不知道內部的原理,我想這篇文章應該能夠幫助到你,實現一個迷你版的 Koa 不會很難。 本文會循序漸進的解析內部原理,包括: 基礎版本的 koacontext 的實現中間件原理及實現 文件結構 applicat ...
  • 目錄 利用nexus搭建npm repository 配置開發環境的registry為我們自己的私有倉庫 編寫自定義vue組件 將自定義組件作為npm包上傳到nexus的repository中 在vue工程中使用使用自己製作的vue組件 nexus搭建npm repository nexus啟動(d ...
  • 前言 本文主要以開發的角度講解Node.js,Npm和Vue。 Node.js學習 什麼是Node.js Node.js簡單來說就是一個IISExpress,提供一個前端Html的獨立運行環境。 安裝Node.js 首先進入官網下載安裝包,官網下載地址:https://nodejs.org/en/d ...
  • 有很多同學留言說,越學越迷茫,不知道該從哪裡下手,今天梳理了一些學習web前端的經驗,以及學習的步驟,分享給大家,希望對你們學習能有幫助。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...