此頁面由社群從英文翻譯而來。了解更多並加入 MDN Web Docs 社群。
for...of
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2015年7月.
for...of 語法執行一個迴圈,該迴圈操作來自可迭代物件的值序列。可迭代物件包括內置物件實例,例如Array、String、TypedArray、Map、Set、NodeList(以及其他 DOM 集合),還包括arguments 物件、由生成器函數生成的生成器,以及用戶定義的可迭代物件。
In this article
嘗試一下
const array1 = ["a", "b", "c"];for (const element of array1) { console.log(element);}// 預期輸出:"a"// 預期輸出:"b"// 預期輸出:"c"語法
for (variable of iterable) statement說明
for...of 迴圈依序逐個操作來自可迭代物件的值。迴圈對值的每次操作稱為一次迭代,而迴圈本身則稱為迭代可迭代物件,每次迭代執行可能參考當前序列值的語句。
當for...of 迴圈在可迭代物件上進行迭代時,它首先調用可迭代物件的[Symbol.iterator]() 方法,該方法回傳一個迭代器,然後重複調用得到的迭代器的next() 方法,以生成要賦予variable 的值序列。
當迭代器完成時(next() 的回傳結果是一個具有done: true 的物件),for...of 迴圈便會退出。與其他迴圈語句一樣,你可以在statement 中使用流程控制語句:
如果for...of 迴圈提前退出(例如遇到break 語句或拋出錯誤),則會調用迭代器的return() 方法來執行任何清理動作。
for...of 的variable 部分可以接受任何在= 運算符之前的東西。只要在迴圈主體內不重新賦值(它可以在迭代之間改變,因為它們是兩個獨立的變數),你可以使用const 來宣告變數;否則,你可以使用let。
const iterable = [10, 20, 30];for (let value of iterable) { value += 1; console.log(value);}// 11// 21// 31備註:每次迭代都會創建一個新的變數。在迴圈主體內重新賦值不會影響可迭代物件(在本例中是一個陣列)中的原始值。
你可以使用解構指派多個局部變數,或者使用屬性訪問子(如for (x.y of iterable))賦值給物件屬性。
然而,有一條特別規則──禁止以async 作為變數名稱,這是無效語法:
let async;for (async of [1, 2, 3]); // SyntaxError: The left-hand side of a for-of loop may not be 'async'.這是為了避免和有效程式碼for (async of => {};;) 出現語法歧異,該程式碼是一個for 迴圈。
範例
>迭代陣列
const iterable = [10, 20, 30];for (const value of iterable) { console.log(value);}// 10// 20// 30迭代字串
字串將依Unicode 編碼位置迭代。
const iterable = "boo";for (const value of iterable) { console.log(value);}// "b"// "o"// "o"迭代 TypedArray
const iterable = new Uint8Array([0x00, 0xff]);for (const value of iterable) { console.log(value);}// 0// 255迭代 Map
const iterable = new Map([ ["a", 1], ["b", 2], ["c", 3],]);for (const entry of iterable) { console.log(entry);}// ['a', 1]// ['b', 2]// ['c', 3]for (const [key, value] of iterable) { console.log(value);}// 1// 2// 3迭代 Set
const iterable = new Set([1, 1, 2, 2, 3, 3]);for (const value of iterable) { console.log(value);}// 1// 2// 3迭代參數物件
你可以迭代arguments 物件來檢查傳給函數的所有參數。
function foo() { for (const value of arguments) { console.log(value); }}foo(1, 2, 3);// 1// 2// 3迭代 NodeList
下面的範例透過迭代一個NodeList DOM 集合,為位於<article> 元素下的段落添加read 類別。
const articleParagraphs = document.querySelectorAll("article > p");for (const paragraph of articleParagraphs) { paragraph.classList.add("read");}迭代用戶定義的可迭代物件
迭代帶有回傳自訂迭代器的[Symbol.iterator]() 方法的物件:
const iterable = { [Symbol.iterator]() { let i = 1; return { next() { if (i <= 3) { return { value: i++, done: false }; } return { value: undefined, done: true }; }, }; },};for (const value of iterable) { console.log(value);}// 1// 2// 3迭代帶有[Symbol.iterator]() 生成器方法的物件:
const iterable = { *[Symbol.iterator]() { yield 1; yield 2; yield 3; },};for (const value of iterable) { console.log(value);}// 1// 2// 3可迭代迭代器(帶有回傳this 的[Symbol.iterator]() 方法的迭代器)是一種相當常見的技術,用來使迭代器在期望可迭代物件的語法中使用,例如for...of。
let i = 1;const iterator = { next() { if (i <= 3) { return { value: i++, done: false }; } return { value: undefined, done: true }; }, [Symbol.iterator]() { return this; },};for (const value of iterator) { console.log(value);}// 1// 2// 3迭代生成器
function* source() { yield 1; yield 2; yield 3;}const generator = source();for (const value of generator) { console.log(value);}// 1// 2// 3提前退出
在第一個迴圈中執行break 會導致迴圈提前退出。迭代器尚未完成,因此第二個迴圈將從第一個迴圈停止的地方接續執行。
const source = [1, 2, 3];const iterator = source[Symbol.iterator]();for (const value of iterator) { console.log(value); if (value === 1) { break; } console.log("這個字串不會被輸出。");}// 1// 另一個使用相同迭代器的迴圈會從上個迴圈的中斷處接續執行。for (const value of iterator) { console.log(value);}// 2// 3// 迭代器已用完。該迴圈不會執行任何迭代。for (const value of iterator) { console.log(value);}// [沒有輸出]生成器實現了return() 方法,當迴圈退出時,該方法會使生成器函數提前回傳,使得生成器在迴圈間不可重複使用。
function* source() { yield 1; yield 2; yield 3;}const generator = source();for (const value of generator) { console.log(value); if (value === 1) { break; } console.log("這個字串不會被輸出。");}// 1// 生成器已用完。該迴圈不會執行任何迭代。for (const value of generator) { console.log(value);}// [沒有輸出]for...of 與for...in 之間的差別
for...in 和for...of 都用於迭代某個東西,它們之間的主要差別在於迭代的對象。
for...in 用於迭代物件的可枚舉字串屬性,而for...of 用於迭代可迭代物件定義的要進行迭代的值。
下面的範例演示了在迭代Array 時,for...of 迴圈和for...in 迴圈之間的差別。
Object.prototype.objCustom = function () {};Array.prototype.arrCustom = function () {};const iterable = [3, 5, 7];iterable.foo = "hello";for (const i in iterable) { console.log(i);}// "0"、"1"、"2"、"foo"、"arrCustom"、"objCustom"for (const i in iterable) { if (Object.hasOwn(iterable, i)) { console.log(i); }}// "0" "1" "2" "foo"for (const i of iterable) { console.log(i);}// 3 5 7iterable 物件繼承了objCustom 和arrCustom 屬性,因為其原型鏈中同時包含了Object.prototype 和Array.prototype。
for...in 迴圈只輸出了iterable 物件的可枚舉屬性。它不會輸出陣列中的元素3、5、7 或"hello",因為它們不是屬性,而是值。它輸出了陣列的索引以及arrCustom 和objCustom,它們是實際的屬性。如果你對為什麼迭代這些屬性感到困惑,可以查看關於陣列迭代和for...in 的工作原理,裡面有更詳細的解釋。
第二個迴圈與第一個迴圈類似,但它使用Object.hasOwn() 來檢查找到的可枚舉屬性是否為物件的自有屬性,即非繼承屬性。如果是,則輸出該屬性。屬性0、1、2 和foo 皆被輸出,因為它們是自有屬性。屬性arrCustom 和objCustom 都沒有被輸出,因為它們是繼承屬性。
for...of 迴圈迭代並輸出iterable 按照可迭代陣列定義要進行迭代的值。物件的元素3、5、7 被輸出,但物件的屬性沒有被輸出。
規範
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-for-in-and-for-of-statements> |