過去,當有一個陣列的內容需要依序取值時,都會使用 for...
迴圈(for loop)的形式將值一一取出,原始碼的結構如下:
var array = ['小明', '杰倫', '漂亮阿姨', '小美']
for (var i = 0; i < array.length; i++) {
const item = array[i];
console.log(i, item);
}
現在,陣列執行迴圈不像過去那麼麻煩,陣列的原型中增加了許多方法可以直接運用(陣列方法可參考),其中的 forEach
基本上可以達到 for...
迴圈的所有需求(基本上用了 forEach
不太會再去使用 for loop)。
相同的結果,使用 forEach
後更容易被閱讀、理解。
array.forEach(function(item, i) {
console.log(i, item)
});
不過實際上這兩者還是略有差異,本篇就來介紹 for 迴圈與 forEach 的那些小差別。
因為 JS 作用域是屬於函式作用域,而 for loop 在執行時使用 var
所建立的變數是屬於在區塊 {}
內,因此 for loop 運行時所定義的變數很常會是建立在 全域 的環境下。
以下範例來說,下列變數 i
就屬於全域的變數。
for (var i = 0; i < array.length; i++) {
const item = array[i];
console.log(i, item);
}
console.log(i); // 4
相對來說 forEach
使用 callback function
就不容易踩到這個雷,不過 for loop 依然可以使用 ES6 的 let, const
來解決作用域的問題。
目前主流的文字編輯器,輸入 for
後預設都會使用 let
來定義索引 i
的變數。
for (let i = 0; i < array.length; i++) {
const item = array[i];
console.log(i, item);
}
console.log(i) // 無法取得 i
雖然 for loop 目前的使用率較不如 forEach
,不過它可中斷運行的方式在 forEach
中是沒有的,如果迴圈中有必要停止運行,就可以使用 for loop 搭配 break
。
for (let i = 0; i < array.length; i++) {
const item = array[i];
if (i === 2) { // 執行到索引 2 就會被中斷
break;
}
console.log(i, item);
}
執行到索引 2 就會被中斷,中斷後的迴圈將不會繼續運行。
JavaScript 中的陣列依據原型的不同,也有另一種分支稱為類陣列(array-like),類陣列中的原型方法與一般定義的陣列就有所不同,其中的方法就可能不包含 forEach
。
函式中的 arguments
就屬於類陣列,它的方法就不包含 forEach
的方法,因此它無法直接運行 forEach
。
function fn() {
console.log(arguments);
// for loop 可以正常運行
for (let i = 0; i < arguments.length; i++) {
const item = arguments[i];
console.log(i, item);
}
// 錯誤:Uncaught TypeError: arguments.forEach is not a function
arguments.forEach(item => {
console.log(item);
});
}
fn('小明', '杰倫', '漂亮阿姨', '小美');
純陣列的原型中可以找到 forEach
的方法。
arguments
類陣列中不包含 forEach
或任何的陣列方法。
類陣列可以直接使用 for loop 來運行它,如果要使用 forEach
的陣列方法也是可行,只要將類陣列透過 ES6 的 “展開” 語法轉換為純陣列即可([...]
)。
如以下程式碼中就透過展開將 arguments
轉變為純陣列 arg
,那麼 arg
變數就可以使用 forEach
的陣列方法。
function fn() {
const arg = [...arguments];
arg.forEach(item => console.log(item))
}
fn('小明', '杰倫', '漂亮阿姨', '小美');
你是屬於 forEach
還是 for...loop
派呢?歡迎留言討論看看喔。