for迴圈是最常用來重複執行某些邏輯的敘述之一。
在 JavaScript 中,它由for關鍵字、包在小括號中的_標頭_,以及包在大括號中、包含迴圈_主體_的程式區塊組成。
for (initialization; condition; step) {
// code that is executed repeatedly as long as the condition is
// true
}
初始化通常會設定計數器變數,條件會檢查迴圈應該繼續還是停止,而遞增步驟會在每次重複結束時將計數器加一。 標頭的各個部分以分號分隔。
const list = ['a', 'b', 'c'];
for (let i = 0; i < list.length; i++) {
// code that should be executed for each item in the array
}
標頭的三個部分都是選用的。 實務上很少這樣用。 你可以在MDN 文件中閱讀更多相關內容。
for迴圈可以巢狀使用,例如用來疊代巢狀(多維)的陣列。
請務必為每個迴圈設定不同的計數器變數。
const coords = [
[1, 2],
[4, 7],
[10, -3],
];
for (let i = 0; i < coords.length; i++) {
for (let j = 0; j < coords[i].length; j++) {
// do something with coords[i][j]
}
}
在迴圈主體中,你可以使用break關鍵字來完全停止迴圈的執行。
相對地,continue關鍵字只會停止目前這次疊代的執行,並繼續進行下一次。
處理巢狀迴圈時,break和continue預設一律只作用於最內層的迴圈。
你可以使用標籤來改變這個行為。
標籤是一個後面接著冒號的識別字名稱。
它會放在迴圈的前面(或上方)。
這樣的標籤可以再和break或continue搭配使用,以指定這個敘述應該作用於哪個迴圈。
outer: for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
// ...
if (j > 5) {
continue outer;
}
// ...
}
}
處理非同步程式碼時,你需要小心正確地宣告計數器變數。
我們來看一個例子:等 1 秒後,用setTimeout以非同步方式將計數器變數加總。
若用var宣告計數器,或用let但在標頭之外宣告,程式碼就不會產生預期的結果。
let sum = 0;
for (var i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 12 instead of 6 (1+2+3)
let sum = 0;
let i;
for (i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// same here, eventually sum will be 12 instead of 6 (1+2+3)
在這兩種情況下,i的作用域並不限於某一次特定的迴圈疊代。
等到計算加總時,i已經達到最終值4,導致加總結果變成4 + 4 + 4 = 12。
只要在標頭內用let宣告計數器,就能避免這個問題。
這會產生一個特殊效果:每次疊代都會取得自己專屬的變數let i,其作用域恰好限於該次迴圈主體的執行。
因此,稍後計算加總時,每個回呼函式都會參照到自己專屬的變數i,而它仍保留著正確的值。
let sum = 0;
for (let i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 6 (1+2+3) as expected