以下是Javascript中可以實現循環的方法:
- For Loop
- While Loop
- Do-While Loop
- For-In Loop
- For-Of Loop
- ForEach Loop
- Map Loop
- Filter Loop
- Reduce Loop
- Some Loop
- Every Loop
- Find Loop
我們將對這些循環方法進行測試,以確定哪種方法最快。
為了比較每個循環的性能,我們將使用 console.time() 和 console.timeEnd() 方法來測量它們的執行時間。
javascript
代碼解讀
復制代碼console.time('My Description');
// Code to measure
console.timeEnd('My Description');
用于測試的任務是:將 5000 萬個項目從一個數組轉移到另一個數組。
javascript
代碼解讀
復制代碼console.time('Array Creation');
const numbersList = Array.from({ length: 50_000_000 }, () => Math.floor(Math.random() * 100));
console.timeEnd('Array Creation');
為確保公平比較,我們將異步運行每個循環。
雖然 For-In 的語法與 For-Of 類似,但它不是為數組設計的,因此不在測試之中。 For-In 更適合迭代具有多個屬性的對象,因為它迭代的是屬性名稱(或鍵)而不是值本身,而與數組一起使用會導致性能問題和意外行為。
scss
代碼解讀
復制代碼(async () => {
await usingForLoop(numbersList);
await usingWhile(numbersList);
await usingDoWhile(numbersList);
await usingForOf(numbersList);
await usingForEach(numbersList);
await usingMap(numbersList);
await usingFilter(numbersList);
await usingReduce(numbersList);
await usingSome(numbersList);
await usingEvery(numbersList);
await usingFind(numbersList);
})()
ForLoop
ini
代碼解讀
復制代碼const usingForLoop = async (array) => {
console.time('FOR LOOP');
const newNumbersList = [];
for (let i = 0; i < array.length; i++) {
newNumbersList.push(array[i]);
}
console.timeEnd('FOR LOOP');
}
while
ini
代碼解讀
復制代碼const usingWhile = async (array) => {
console.time('WHILE');
let i = 0;
const newNumbersList = [];
while (i < array.length) {
newNumbersList.push(array[i]);
i++;
}
console.timeEnd('WHILE');
}
doWhile
ini
代碼解讀
復制代碼const usingDoWhile = async (array) => {
console.time('DO WHILE');
let i = 0;
const newNumbersList = [];
do {
newNumbersList.push(array[i]);
i++;
} while (i < array.length);
console.timeEnd('DO WHILE');
}
ForOf
javascript
代碼解讀
復制代碼const usingForOf = async (array) => {
console.time('FOR OF');
const newNumbersList = [];
for (const item of array) {
newNumbersList.push(item);
}
console.timeEnd('FOR OF');
}
ForEach
javascript
代碼解讀
復制代碼const usingForEach = async (array) => {
console.time('FOR EACH');
const newNumbersList = [];
array.forEach((item) => newNumbersList.push(item));
console.timeEnd('FOR EACH');
}
Map
typescript
代碼解讀
復制代碼const usingMap = async (array) => {
console.time('MAP');
const newNumbersList = array.map((number) => number);
console.timeEnd('MAP');
}
Filer
javascript
代碼解讀
復制代碼const usingFilter = async (array) => {
console.time('FILTER');
const newNumbersList = array.filter((item) => true);
console.timeEnd('FILTER');
}
Reduce
javascript
代碼解讀
復制代碼const usingReduce = async (array) => {
console.time('REDUCE');
const newNumbersList = array.reduce((acc, item) => {
acc.push(item);
return acc;
}, []);
console.timeEnd('REDUCE');
}
Some
javascript
代碼解讀
復制代碼const usingSome = async (array) => {
console.time('SOME');
const newNumbersList = [];
array.some((item) => {
newNumbersList.push(item);
return false;
});
console.timeEnd('SOME')
}
Every
javascript
代碼解讀
復制代碼const usingEvery = async (array) => {
console.time('EVERY');
const newNumbersList = [];
array.every((item) => {
newNumbersList.push(item);
return true;
});
console.timeEnd('EVERY')
}
Find
javascript
代碼解讀
復制代碼const usingFind = async (array) => {
console.time('FIND');
const newNumbersList= [];
array.find((item) => {
newNumbersList.push(item);
return false;
});
console.timeEnd('FIND')
}
任務運行了五次,顯示的測量值是計算得出的平均值。
測試平均結果如下:
從結果可以看出,前5名分別是:
- Map
- For Loop
- While
- Do While
- For Each
有趣的是只有Map是一個函數調用,其余的都是循環體。
另外該測試僅針對一項特定任務進行的,不同測試用例可能會有不同的結果,不同的內存或者CPU也會有不一樣的表現。從本次測試的結果,我們可以看到Map 和 For Loop 的性能是最好的。令人失望的是For-Of,相對于For Loop,作為新出的一個API竟然效率這么拉跨。
Map每次循環都需要調用回調函數,理論上不應該比For Loop更快。但現代 JavaScript 引擎(如 V8)對高階函數(如 map、filter 等)進行了高度優化,尤其是對數組的處理。引擎內部可能會針對這些高階函數應用特定的優化策略,減少不必要的操作,進而提升性能。而且 map 是一個專門用于遍歷數組并返回新數組的高階函數,V8 等引擎能夠更好地預測和優化其內部的操作路徑。而 for loop 是更通用的控制結構,可能沒有這些特定的優化。
結論
從測試結果看Map和For Loop的循環效率相差不大,大家可以根據需要做選擇。map 無法中途退出,但可以返回一個新的數組。