前言
最近感覺自己對數組遍歷的方法有點混亂,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多種數據結構的遍歷方法,不僅可以遍歷數組,還可以遍歷Map
、Set
這兩種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循環
、forEach
、for...of
、map
、for...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( )
按功能需要來使用即可。