JS數組的幾種遍歷方法

前言

最近感覺自己對數組遍歷的方法有點混亂,for循環、forEach( )、map( )等方法混合使用,沒有一個統一的規范,所以就打算總結一下。

ES5中的數組遍歷方法

ES5為數組定義了5個迭代方法。每個方法都接受兩個參數:要在每一項上運行的函數和(可選的)運行該函數的作用域對象——影響 this 的值。
而傳入的函數又可以接受三個參數:當前遍歷的數組項的值,該項在數組中的位置和數組對象本身。

every( )

對數組中的每一項運行給定函數,如果該函數對每一項都返回true,則every( )返回true。例如:

    let numbers = [1, 2, 3, 4];
    let everyResult = numbers.every((item, index, array)=>{
        return item > 1;
    })
    console.log(everyResult);  // 輸出 false

filter( )

即對數組中的每一項運行給定函數,然后返回該函數會返回true的項。從名字就看得出來,這個方法是用來過濾數組項的,例如:

    let numbers = [1, 2, 3, 4];
    let filterResult = numbers.filter((item, index, array)=>{
        return item > 1;
    })
    console.log(filterResult);  // 輸出 [2, 3, 4]

forEach( )

對數組的每一項運行給定函數。forEach方法是唯一一個沒有返回值的,純粹用來遍歷數組。

    let numbers = [1, 2, 3, 4];
    numbers.forEach((item, index, array)=>{
        // 執行某些操作
    })

map( )

對數組的每一項運行給定函數,返回每次函數調用的返回值組成的數組。map方法就是有返回值的forEach方法,例如:

    let numbers = [1, 2, 3, 4];
    let mapResult = numbers.map((item, index, array)=>{
        return item * 2;
    })
    console.log(mapResult); // 輸出 [2, 4, 6, 8]

some( )

對數組的每一項運行給定函數,如果該函數對任一項返回true,則some( )就返回true。some和every就像 ||&&,some是只要有一項滿足,就返回true。

    let numbers = [1, 2, 3, 4];
    let someResult = numbers.some((item, index, array)=>{
        return item > 3;
    })
    console.log(someResult);  // 輸出 true

ES5的這幾個迭代方法,如果是只對item(當前遍歷的數組項)進行操作,是不會改變原數組的,但是也可以通過給定函數中接收的index參數來改變原數組

除了ES5這幾個方法,還有常見的簡單for循環和ES6的for...of。

for...of

ES6借鑒了Java、Python等語言,引入了for...of循環。for...of主要用來統一ES6多種數據結構的遍歷方法,不僅可以遍歷數組,還可以遍歷MapSet這兩種ES6新推出的數據結構。只要具有iterator接口的數據結構,就可以用for...of循環來遍歷。還可以遍歷某些類似數組的對象,比如arguments對象、DOM NodeList 對象。

let numbers = [1, 2, 3, 4];
for(let item of numbers){
    console.log(item);
}
//輸出
// 1
// 2
// 3
// 4

有關ES6新特性的內容,可以參考阮一峰老師的ES6入門教程

不推薦使用for...in來遍歷數組,只用來遍歷對象的屬性

性能分析

這里主要測試一下for循環forEachfor...ofmapfor...in這幾個方法遍歷一個長度為100000的數組所耗費的時間。

//測試數據: arr = [1,2,3,4,...,99999,100000];

//普通for循環
console.time('普通for循環');
for(let i=0; i<arr.length; i++){

}
console.timeEnd('普通for循環')
//控制臺輸出 => 普通for循環: 0.923095703125ms


//forEach循環
console.time('forEach循環');
arr.forEach((item)=>{

})
console.timeEnd('forEach循環')
//控制臺輸出 => forEach循環: 1.973876953125ms


console.time('for...of循環');
for(let item of arr){

}
console.timeEnd('for...of循環')
//控制臺輸出 => for...of循環: 3.5810546875ms


//for...in循環
console.time('for...in循環');
for(let item in arr){
    
}
console.timeEnd('for...in循環')
//控制臺輸出 => for...in循環: 15.35693359375ms


//map循環循環
console.time('map循環');
arr.map((item) => {
    
})
console.timeEnd('map循環')
//控制臺輸出 => map循環: 19.4990234375ms

可能由于電腦配置等問題,這里你的控制臺輸出可能會不一樣,甚至你刷新一下瀏覽器,兩次的輸出也會不一致。這里map( )居然比for...in的性能還低,印象中是for...in最低的,可能是因為測試的次數太少,有待研究。

總結

從性能上來說,for循環 > forEach > for...of > for...in > map,所以一般來說使用for循環是性能最高的,但是寫法稍微復雜了點。但是性能好和要使用哪種遍歷方法并沒有太大關系,以現在的硬件水平來說,這里的性能差異完全可以忽略。所以一般來說,還需要考慮語義和功能需求。

如果你需要將數組按照給定規則轉換并返回該結果數組,就使用map

如果你需要進行簡單的遍歷,用 forEach 或者 for of,但是 forEach 不能通過return和break語句來終止循環,所以如果需要中途終止循環,就使用 for...of或者 for循環

如果是在遍歷數組的同時,需要改變原數組中的對應項,就用for循環

for...in會把數組所擁有可枚舉的屬性都遍歷一次,所以可能會有意想不到的結果,不推薦用來遍歷數組。

另外的三個,every( )filter( )some( )按功能需要來使用即可。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。