深入理解ES6 008【學習筆記】

迭代器(Iterator)和產生器(Generator)

這項新特性對於高效的資料處理而言是不可或缺的,你也會發現在語言的其他特性中也都有迭代器的蹤影:新的for-of 迴圈、展開運算子(...)、甚至連非同步程式設計都可以使用迭代器。

迭代器是一種特殊的物件,它具有一些專門為迭代過程設計的專有介面,所有的迭代器物件都有一個next()方法,每次呼叫都回傳一個結果物件(形如:{value:true|false,next(){}})。

function createIterator(items){
  var i = 0;
  return {
    next:function(){
      let done = (i>=items.length);
      let value = !done?items[i++];undefined;
      return {
        done,
        value
      }
    }
  }
}
var iterator = createIterator([1,2,3])
console.log(iterator.next()); // {value:1,done:false}
console.log(iterator.next()); // {value:2,done:false}
console.log(iterator.next()); // {value:3,done:false}
console.log(iterator.next()); // {value:undefined,done:true}
// 之後所有呼叫都會回傳相同內容
// {value:undefined,done:true}

產生器

產生器是一種回傳迭代器的函式,透過function關鍵字後的星號(*)來表示,函式中會用到新的關鍵字 yield。星號可以緊挨著function關鍵字,也可以在中間添加一個空格

// 生成器
function *createIteator(){
  yield 1;
  yield 2;
  yield 3;
}

// 生成器的呼叫方式與普通函式相同,只不過回傳的是一個迭代器
let iterator = createIteator();

console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3

產生器函式最有趣的部分大概是,每當執行完一條yield語句後函式就會自動停止執行。執行yield 1之後,函式便不再執行其他任何語句,直到再次呼叫迭代器的 next() 才會繼續執行yield 2

使用yield關鍵字可以回傳任何值或表達式,所以可以透過產生器函式批量地給迭代器添加元素,也可以在迴圈中使用yield關鍵字

yield後面的值會放在迭代器回傳值的 value 中

function *createIterator(items){
  for(let i=0;i<items.length;i++){
    yield items[i];
  }
}
let iterator = createIterator([1,2,3])

console.log(iterator.next()) // {value:1,done:false}
console.log(iterator.next()) // {value:2,done:false}
console.log(iterator.next()) // {value:3,done:false}
console.log(iterator.next()) // {value:undefined,done:true}
// 之後所有的呼叫都會回傳相同內容
console.log(iterator.next()) // {value:undefined,done:true}

產生器函式表達式

let createIterator = function *(items){
  for(let i=0;i<items.length;i++){
    yield items[i];
  }
}
let iterator = createIterator([1,2,3])

console.log(iterator.next()) // {value:1,done:false}
console.log(iterator.next()) // {value:2,done:false}
console.log(iterator.next()) // {value:3,done:false}
console.log(iterator.next()) // {value:undefined,done:true}
// 之後所有的呼叫都會回傳相同內容
console.log(iterator.next()) // {value:undefined,done:true}

產生器物件的方法

let o={
  createIterator:function *(items){
    for(let i=0;i<items.length;i++){
      yield items[i];
    }
  }
}
// 或簡寫
let o1={
  *createIterator(items){
    for(let i=0;i<items.length;i++){
      yield items[i];
    }
  }
}

可迭代物件和 for-of 迴圈

可迭代物件具有Symbol.iterator屬性,是一種與迭代器密切相關的物件。Symbol.iterator透過指定的函式可以回傳一個作用於附屬物件的迭代器。ES6 所有集合物件(陣列、Set 集合及 Map 集合)和字串都是可迭代物件,這些物件都有預設的迭代器。

由於產生器預設會為Symbol.iterator屬性賦值,因此所有透過產生器建立的迭代器都是可迭代物件。

存取預設迭代器

let values = [1,2,3];
let iterator = values[Symbol.iterator]();

console.log(iterator.next()) // {value:1,done:false}
console.log(iterator.next()) // {value:2,done:false}
console.log(iterator.next()) // {value:3,done:false}
console.log(iterator.next()) // {value:undefined,done:true}

由於具有Symbol.iterator屬性的物件都有預設的迭代器,因此可以用它來偵測物件是否為可迭代物件

function isIterator(object){
  return typeof object[Symbol.iterator] === "function";
}
console.log(isIterator([1,2,3])); // true
console.log(isIterator("Hello")); // true
console.log(isIterator(new Map())); // true
console.log(isIterator(new Set())); // true
console.log(isIterator(new WeakMap())); // false
console.log(isIterator(new WeakSet())); // false

建立可迭代物件

預設情況下,開發者定義的定義都是不可迭代物件,但如果給Symbol.iterator屬性添加一個產生器

let collection = {
  items:[],
  *[Symbol.iterator](){
    for(let item of this.items){
      yield items;
    }
  }
}
collection.items.push(1)
collection.items.push(2)
collection.items.push(3)

for(let x of collection){
  console.log(x)
}

內建迭代器 集合物件迭代器

  • entries()
  • values()
  • keys()

字串迭代器

var message = "A 𠮷 B";

for(let c of message){
  console.log(c)
}

NodeList 迭代器

var divs = document.getElementByTagName("div");

for(let div of divs){
  console.log(div.id)
}

展開運算子與非陣列可迭代物件

let set = new Set([1,2,3,3,3,4,5]),
array = [...set];
console.log(array); // [1,2,3,4,5]

let map = new Map([["name","Nicholas"],["age",25]]),
array = [...map];

console.log(array) // [["name","Nicholas"],["age",25]]

進階迭代器功能

可以用迭代器的 next() 方法的回傳值,也可以在產生器內部使用 yield 關鍵字來產生值,如果給迭代器的next()方法傳遞參數,則這個參數的值就會替代產生器內部上一條yield語句的回傳值。而如果要實現更多像非同步程式設計這樣的高級功能

function *createIterator() {
let first = yield 1;
let second = yield first + 2;

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4334

(0)
Walker的頭像Walker
上一篇 2025年3月8日 12:52
下一篇 2025年3月8日 12:51

相關推薦

  • Node 深入淺出(聖思園教育) 002【學習筆記】

    node 的套件管理機制和載入機制 npm search xxxnpm view xxxnpm install xxx nodejs 檔案系統操作的 api Node.js 的 fs 模組提供同步(Sync)與基於回呼/Promise 的非同步 API,可以操作本機檔案與目錄。日常開發中常用的能力包括讀取、寫入、追加、刪除、遍歷目錄、監聽變化等。以下範例基於 C…

    個人 2025年11月24日
    23100
  • 深入理解ES6 011【學習筆記】

    Promise與異步程式設計 因為執行引擎是單執行緒的,所以需要追蹤即將執行的程式碼,那些程式碼會被放在一個任務佇列中,每當一段程式碼準備執行時,都會被新增到任務佇列中,每當引擎中的一段程式碼結束執行時,事件迴圈會執行佇列中的下一個任務。 Promise 相當於異步操作結果的佔位符,它不會去訂閱一個事件,也不會傳遞一個回呼函式給目標函式,而是讓函式回傳一個 Promise,就像這樣…

    個人 2025年3月8日
    1.1K00
  • Go工程師體系課 001【學習筆記】

    轉型 想在短時間系統轉到Go工程的理由 提高CRUD,無自研框架經驗 提升技術深度,做專、做精需求的同學 進階工程化,擁有良好開發規範和管理能力的 工程化的重要性 高階開發的期望 良好的程式碼規範 深入底層原理 熟悉架構 熟悉k8s的基礎架構 擴展知識廣度,知識的深度,規範的開發體系 四個大的階段 Go語言基礎 微服務開發的(電商專案實戰) 自研微服務 自研然後重…

    個人 2025年11月25日
    28100
  • Go工程師體系課 008【學習筆記】

    訂單及購物車 先從庫存服務中將 srv 的服務程式碼框架複製過來,搜尋取代對應的名稱(order_srv) 加密技術基礎 對稱式加密(Symmetric Encryption) 原理: 使用同一個金鑰進行加密和解密 就像一把鑰匙,既能鎖門也能開門 加密速度快,適合大量資料傳輸 使用情境: 本機檔案加密 資料庫內容加密 大量資料傳輸時的內容加密 內部系統間的快速通…

    個人 2025年11月25日
    19800
  • 無畏前行,拳釋力量 🥊💪

    拚搏,是一種態度。生活就像一場比賽,沒有捷徑可走,只有不斷訓練、突破、超越,才能站上屬於自己的舞台。這不僅是一種對抗,更是一種自我的覺醒——敢於迎戰,敢於挑戰,敢於成為更強的自己。 運動中的拚搏精神 無論是拳擊、跑步,還是力量訓練,每一次出拳、每一次揮汗、每一次咬牙堅持,都是對身體與心靈的磨練。拚搏不是單純的對抗,而是一種態度——面對挑戰,不退縮;面對失敗,…

    個人 2025年2月26日
    1.3K00
歡迎🌹 Coding never stops, keep learning! 💡💻 光臨🌹