JavaScript中有很多遍歷數組的方式,比較常見的是for(var i=0;i<arr.length;i++){},以及for...in...循環等,這些遍歷都有各自的優缺點,下面來看看各種JS的遍歷對比:
1.for...in...
1).index索引為字符串型數字,不能直接進行幾何運算。
2).遍歷順序有可能不是按照實際數組的內部順序。
3).使用for in會遍歷數組所有的可枚舉屬性,包括原型。例如上栗的原型方法method和name屬性。
Array.prototype.myfun=function(){ alert('myfun'); } var arr = [0,1,2,3]; for(var i in arr){ console.log(arr[i]); } console.log(Array.prototype)
運行結果:
上面的例子很好的反映了for...in...循環的缺點,原本只想循環取出該數組的數據,但是由於之前給數組添加了原型函數,導致循環的結果多了一個函數。這種場景我在使用lodop打印控件寫打印功能時遇到過,打印的內容我用for...in...循環打印了,結果打印的結果莫名其妙多了一串代碼,排查了很久才發現原來是lodop.js將Array數組的原型添加了方法,導致循環的時候將該方法也遍歷到了,所以for...in...循環最好使用在遍歷對象上,不要用來遍歷數組。
2.普通for循環
let arr = [1,2,3,4,5];
for (var index = 0; index < arr.length; index++) {
console.log(arr[index]);
}
這是最原始的寫法,也是應用比較多的循環方式,但寫法較為麻煩,性能有優化空間。
3.優化for循環
var arr = [0,1,2,3];
for(j=0,len=arr.length;j<len;j++){
console.log(arr[j]);
}
使用臨時變量,將長度緩存起來,避免重復獲取數組長度,當數組較大時優化效果才會比較明顯。這種方法基本上是所有循環遍歷方法中性能最高的一種,所以推薦使用這種循環。
4.forEach循環
let arr = [1,2,3,4,5];
arr.forEach((element,index) => {
console.log(element);
});
forEach循環是數組自帶的方法,這種方式循環十分方便,不需要獲取數組長度即可循環,但是有一個問題,在循環的中途無法跳出forEach
循環,break
命令或return
命令都不能奏效,也就是說一循環必然會執行完畢,不能靈活運用於多種情況。
5.for...of...循環
for…of是ES6新增的遍歷方式,它提供了統一的遍歷機制。所有實現了[Symbol.iterator]接口的對象都可以被遍歷。for...of
循環可以使用的范圍包括數組、Set 和 Map 結構、某些類似數組的對象(比如arguments
對象、DOM NodeList 對象)、Generator 對象,以及字符串。
優點:
- 有着同
for...in
一樣的簡潔語法,但是沒有for...in
那些缺點 - 不同用於
forEach
方法,它可以與break
、continue
和return
配合使用 - 提供了遍歷所有數據結構的統一操作接口
下面是一個使用break語句,跳出for...of
循環的例子。
for (var n of arr) {
if (n > 2) break;
console.log(n);
}
上面的例子,會輸出斐波納契數列小於等於2的項。如果當前項大於2,就會使用break
語句跳出for...of
循環。
for...of獲取索引
entries
返回一個遍歷器對象,用來遍歷[鍵名, 鍵值]
組成的數組。對於數組,鍵名就是索引值;對於 Set,鍵名與鍵值相同。Map 結構的 Iterator 接口,默認就是調用entries
方法。keys
返回一個遍歷器對象,用來遍歷所有的鍵名。values
返回一個遍歷器對象,用來遍歷所有的鍵值。let arr = ['a', 'b', 'c']; for (let pair of arr.entries) { console.log(pair); } // [0, 'a'] // [1, 'b'] // [2, 'c']
類似數組的對象
類似數組的對象包括好幾類。下面是for...of
循環用於字符串、DOM NodeList 對象、arguments
對象的例子。
// 字符串 let str = "hello";
for (let s of str) {
console.log(s);
// h e l l o
} // DOM NodeList對象 let paras = document.querySelectorAll("p"); for (let p of paras) {
p.classList.add("test");
} // arguments對象 function printArgs { for (let x of arguments) { console.log(x); }
}
printArgs('a', 'b'); // 'a'
// 'b'
並不是所有類似數組的對象都具有 Iterator 接口,一個簡便的解決方法,就是使用Array.from
方法將其轉為數組。
let arrayLike = { length: 2, 0: 'a', 1: 'b' }; // 報錯 for (let x of arrayLike) {
console.log(x);
} // 正確 for (let x of Array.from(arrayLike)) { console.log(x); // 'a' // 'b' }
普通的對象
對於普通的對象,for...of
結構不能直接使用,會報錯,必須部署了 Iterator 接口后才能使用。
let es6 = { edition: 6, committee: "TC39", standard: "ECMA-262" }; for (let e in es6) { console.log(e); } // edition
// committee
// standard for (let e of es6) { console.log(e); } // TypeError: es6 is not iterable
解決方法是,使用Object.keys
方法將對象的鍵名生成一個數組,然后遍歷這個數組。
let es6 = { edition: 6, committee: "TC39", standard: "ECMA-262" }; for (var key of Object.keys(es6)) { console.log(key + ': ' + es6[key]); }
借鑒於https://www.cnblogs.com/wangxiayun/p/10194806.html