Array.prototype.forEach()
的用法自知道Array
有forEach
的方法後,我自己是還蠻愛用的。
var names = ["World", "Bob", "Alice"]
names.forEach(name => console.log(`Hello, ${name}`))
並且與其他多數Array
支援的callback方法一樣,有多個很有效的參數:
var names = ["World", "Bob", "Alice"]
names.forEach((name, idx, arr) => {
console.log(`Hello, ${name}`)
arr[idx] += "."
})
console.log(names); // ["World.", "Bob.", "Alice."]
我們甚至可以用而外的thisArg
來處理某些事情:
var obj = {
"World": undefined,
"Bob": undefined
};
function checkHello(name) {
if (name in this)
return void (this[name] = "Yes");
return void (this[name] = "No");
}
var names = ["World", "Bob", "Alice"];
names.forEach(checkHello, obj);
console.table(obj);
結果:
name | result |
---|---|
World | Yes |
Bob | Yes |
Alice | No |
在通常情況下,不會由瀏覽器處理大量的資料。通常而言forEach()
的需要時間基本沒有什麼差別:
var arr = Array(10).fill("hello")
console.time('for-in')
for(let i in arr) {
console.log(arr[i])
}
console.timeEnd('for-in')
console.time('forEach')
arr.forEach(e => {
console.log(e)
})
console.timeEnd('forEach')
下面是我在Google Chrome下簡單測試的結果。
for-in: 2.2939453125 ms
forEach: 1.30517578125 ms
可以認爲差異上僅僅是誤差,無法認爲是for-in
還是forEach()
比較好。
但還是遇過需要在意性能的時候。在我工作上遇到過資料在瀏覽器處理更爲簡單、方便的情況。而且需要處理的資料量需要到了在意是使用for-in
還是forEach()
的情況。
實際上,是使用的套件在一次更新後,有大幅度的時間減少。去了解了一下調整方式,才留意到這部分有性能影響。
因為填充後(.fill()
)的輸出必會需要大量的IO。這裡先證明empty Array在for-in
和forEach
有同樣最終行為(for-of
應該可以視與for-in
同樣情況)。
var arr = Array(10)
console.time('for-in')
for(let i in arr) {
console.log('check', arr[i])
}
console.timeEnd('for-in')
console.time('forEach')
arr.forEach(e => {
console.log('check', e)
})
console.timeEnd('forEach')
可以發現兩種情況都沒有任何輸出,說明兩著都略過了empty
的部份。接著就使用非常大的Array
試試
var arr = Array(1000000000)//.fill("hello")
console.time('for-in')
for(let i in arr) {
console.log(arr[i])
}
console.timeEnd('for-in')
console.time('forEach')
arr.forEach(e => {
console.log(e)
})
console.timeEnd('forEach')
以下是我在 Google Chrome 的測試結果:
for-in: 0.027099609375 ms
forEach: 27090.889892578125 ms
Mozill Firefox Browser的測試結果:
for-in: 0ms - 計時器停止
forEach: 5663ms - 計時器停止
這次就有明顯差距。for-in
需要的時間明顯比forEach
的時間少。
相比起for-in
,forEach()
是個方法的調用。其次,forEach()
接受的callback同樣是一個Function
。這意味著每次處理每個內容,都是一次次的函式調用。還記得之前所說的Call Stack嗎?
函式的調用基本都需要函式堆疊分配、函式執行、堆疊回收的過程。
這樣的行為造成相比for-in
,forEach()
需要更多的操作行為。但並不是真的所有函式調用都有這樣的成本,有幾種優化的處理方式,甚至有些是編譯器或直譯器直接的行爲。
(雖然有寫過一篇相關的草稿,不過那並不算是Web技術,主題更接近 Software Development 吧)
本文同時發表於我的隨筆