簡單瞭解JS中的幾種遍歷
忙了好一段時間,專案上線後終於有那麼一點點空檔期靜下來整理一些問題了。當我們在開發專案的時候,用到遍歷的地方肯定少不了,那麼我們有那麼多的遍歷方法,在不同情況下用那種方法會更優雅而且還沒bug呢?
首先,我在這裡先列出幾種常見的遍歷機制,然後針對部分來做一個我對它的理解,有不同看法的老鐵也可以分享一下,下面是我列出來的幾種遍歷的方法,另外我們常用來中斷迴圈的語句我在這裡簡單的提一下:
a、continue: 中斷本次迴圈;
b、return和break直接跳出迴圈。
var arr = [1, 2, 3] for(var i = 0; i < arr.length; i++) {
//do something
};
// for...of...
for(var i of arr) {
//do something
};
// for...in..
for(var i in arr) {
//do something
};
// forEach()
arr.forEach((item, index, arr) => {
//do something});
});
// map()
arr.map((value,index,array) => {
//do something
});
在開發上一個專案的時候,我在用for...in...這個方法遍歷的時候就遇到一個詭異的bug,在android手機是完美的展示,但是在iPhone手機的時候,就出現了遍歷後的資料竟然是翻倍的,而且資料是重複的。然後我就想著用array.forEach的方法,來解決問題總該行來吧,在正常邏輯的情況下是可以解決問題的,但是,在稍微複雜的邏輯了,有時候我們要中斷forEach遍歷時,這時候就會顯得軟弱無力了,因為在forEach的遍歷機制裡是不支援中斷遍歷的,然後我只能尋求其他的解決方案了。
下面我在這對上述列舉的遍歷方法逐個逐個的分析一下,有些分析不到位的,或者有不同的看法的老鐵們請分享你的看法:
1. 普通的for迴圈
var arr = [1, 2, 3] for(var i = 0; i < arr.length; i++) { // 這裡的i是代表陣列的下標
console.log(i); // 0, 1, 2
};
最簡單的一種,正常用的話也不會出現什麼問題,想中斷也可以中斷,效能上也還可以。
2. 優化版的for迴圈
var arr = [1, 2, 3] ;
for(var i = 0, len = arr.length; i < len; i++) { // 這裡的i是代表陣列的下標
console.log(i); // 0, 1, 2
};
使用臨時變數,將長度快取起來,避免重複獲取陣列長度,當陣列較大時優化效果才會比較明顯。這種方法基本上是所有迴圈遍歷方法中效能最高的一種,並且這一型別的for迴圈可以通過用break來中斷迴圈,如下圖所示:
3. for...of...遍歷(這種遍歷支援ES6)
var arr = [1, 2, 3] ;
for(var item of arr) { // item代表陣列裡面的元素
console.log(item); // 1, 2, 3
};
1、 這是最簡潔、最直接的遍歷陣列元素的語法
2、 這個方法避開了for-in迴圈的所有缺陷
3、 與forEach()不同的是,它可以正確響應break、continue和return語句
4、效能要好於forin,但仍然比不上普通for迴圈
4. forEach()
var arr = [1, 2, 3];
arr.forEach((item, index, arr) => { // item為arr的元素,index為下標,arr原陣列
console.log(item); // 1, 2, 3
console.log(index); // 0, 1, 2
console.log(arr); // [1, 2, 3]
});
這種遍歷便捷還是挺便捷的,看起來優雅,對目標陣列的操作很人性化,要元素給元素,要下標給下標,但是當某種情況你想中斷遍歷的時候,你就會感覺它就像雞肋,食之無味,棄之可惜。由於foreach是Array型自帶的,對於一些非這種型別的,無法直接使用(如NodeList),所以才有了這個變種,使用這個變種可以讓類似的陣列擁有foreach功能。而且forEach的效能也會比普通的for迴圈弱。又下面的例子我們可以看到,我們常用的return false是可以終止程式碼繼續往下執行的,但是在forEach遍歷中,並沒有終止迴圈,所以在用forEach的時候,要考慮使用場景了。
5.some()
var arr = [1, 2, 3];
arr.some((item, index, arr) => { // item為陣列中的元素,index為下標,arr為目標陣列
console.log(item); // 1, 2, 3
console.log(index); // 0, 1, 2
console.log(arr); // [1, 2, 3]
});
some作為一個用來檢測陣列是否滿足一些條件的函式存在,同樣是可以用作遍歷的函式簽名同forEach,有區別的是當任一callback返回值匹配為true則會直接返回true,如果所有的callback匹配均為false,則返回false。
some() 方法會依次執行陣列的每個元素:
- 如果有一個元素滿足條件,則表示式返回true , 剩餘的元素不會再執行檢測。
- 如果沒有滿足條件的元素,則返回false。
7. every()
var arr = [1, 2, 3];
arr.every((item, index, arr) => { // item為陣列中的元素,index為下標,arr為目標陣列
return item > 0; // true
return index == 0; // false
});
every() 方法用於檢測陣列所有元素是否都符合指定條件(通過函式提供)。
every() 方法使用指定函式檢測陣列中的所有元素:
- 如果陣列中檢測到有一個元素不滿足,則整個表示式返回 false ,且剩餘的元素不會再進行檢測。
- 如果所有元素都滿足條件,則返回 true。
8. for...in...遍歷
var arr = [1, 2, 3] for(var item in arr) { // item遍歷陣列時為陣列的下標,遍歷物件時為物件的key值
console.log(item); // 0, 1, 2
};
for...in更多是用來遍歷物件,很少用來遍歷陣列, 不過 item 對應與陣列的 key值,建議不要用該方法來遍歷陣列,因為它的效率是最低的。
9. filter()
var arr = [1, 2, 3];
arr.filter(item => { // item為陣列當前的元素
return item > 1; // [2, 3]
});
filter() 方法建立一個新的陣列,新陣列中的元素是通過檢查指定陣列中符合條件的所有元素。
10. map()
var arr = [1, 2, 3];
arr.map(item => { // item為陣列的元素
console.log(item); // 1, 2, 3
return item * 2; // 返回一個處理過的新陣列[2, 4, 6]
});
map() 方法返回一個新陣列,陣列中的元素為原始陣列元素呼叫函式處理後的值。
map() 方法按照原始陣列元素順序依次處理元素。
這種方式也是用的比較廣泛的,雖然用起來比較優雅,但實際效率還比不上foreach
上述簡單的介紹了各種遍歷的方法。
在前面我有提到一個蘋果手機遍歷出現資料重複的bug,那麼我在這裡做一個用for...in...案例,首先來看看程式碼:
for (let item in this.currentForm) {
var subFormDataObj = {}; if (this.currentForm[item].isRequired === 2 && !this.currentForm[item].subjectValue && this.currentForm[item].subjectType != 5) { this.isSubmit = true; this.hideLoading(); this.Toast('尚有資料未完成,提交失敗!'); return false;
} else { if (this.expressionTest(this.currentForm[item].subjectValue)) { this.Toast('內容不能含有表情符,請重新輸入!'); this.isSubmit = true; this.hideLoading(); return false;
} if (this.currentForm[item].subjectName.indexOf('手機號') > -1) { if(!this.checkPhone(this.currentForm[item].subjectValue)) { this.isSubmit = true; this.hideLoading(); return false;
};
}
subFormDataObj.subjectId = this.currentForm[item].subjectId;
subFormDataObj.subjectValue = this.currentForm[item].subjectValue;
subFormDataObj.picture = this.currentForm[item].picurl;
subFormDataObj.isRequired = this.currentForm[item].isRequired; if (this.currentForm[item].subjectType == 5) { if (this.listPicStr == '') { this.isSubmit = true; this.hideLoading(); this.Toast('尚有資料未完成,提交失敗!'); return false;
} else { // subFormDataObj.picture = "data:image/jpeg;base64," + this.listPicStr.replace(/data:image\/jpeg;base64,/g,'') || '';
}
}
subFormData.push(subFormDataObj);
}
};
alert(JSON.stringify(subFormData));
我們看一下安卓手機和蘋果手機alert出來的資料有什麼區別:在截圖中我們就可以發現,蘋果手機整體遍歷了2輪,這樣個結果是不是很詭異?是的我也覺得很詭異,怎麼來解決呢,很多很學會想到一些方法,比如用陣列去重的方法,並且es6的去重方法很優雅(var newArr = Array.from(new Set(subFormData))),或者其他去重的方法,這樣做並沒有什麼不好,比較方法有千千萬,喜歡就好。當時因為考慮到裡面的邏輯問題,我就直接改了一行程式碼,用了最普通的方法,因為效能上會有優勢,所以我就用了普通的for迴圈解決了這個問題。
換了一種遍歷方法後,這個問題就解決了,在這裡簡單的做了一些開發時遇到的坑做了一些總結,有不同看法的各路大神,跪求分享!!!
相關文章
- JS遍歷物件的幾種方法JS物件
- JavaScript中遍歷的幾種方法JavaScript
- JS中陣列的遍歷方法(3種)JS陣列
- JS中的遍歷JS
- 遍歷陣列的幾種方法陣列
- js中我最常用的幾種遍歷處理資料的方法梳理JS
- 遍歷資料夾的幾種方式
- C++ Vector遍歷的幾種方式()C++
- Node.js簡單瞭解Node.js
- 對於JS模組的簡單瞭解JS
- js的map遍歷和array遍歷JS
- JS遍歷物件屬性的7種方式JS物件
- JavaScript 中的遍歷詳解JavaScript
- jquery中each的三種遍歷方法jQuery
- java中遍歷Map的4種方法Java
- js遞迴遍歷講解JS遞迴
- 有關js各種陣列遍歷JS陣列
- php手冊 php陣列的遍歷有哪幾種方式?php陣列如何遍歷?PHP陣列
- JS中遍歷陣列、物件的方式JS陣列物件
- js如何遍歷陣列中的元素JS陣列
- JS筆記(2) JS中的迴圈遍歷JS筆記
- JS 物件的遍歷JS物件
- JavaScript 各種遍歷方式詳解JavaScript
- 【Java中遍歷Map物件的4種方法】Java物件
- JavaScript中的12種迴圈遍歷方法JavaScript
- js宣告陣列的幾種方式簡單介紹JS陣列
- java集合遍歷的幾種方式總結及比較Java
- 邦芒簡歷:瞭解簡歷中的求職動機怎麼寫很重要求職
- 簡單瞭解 MySQL 中相關的鎖MySql
- javascript遍歷物件的屬性簡單介紹JavaScript物件
- JS 基礎篇(七):JS中的遍歷函式JS函式
- JS遍歷物件的方式JS物件
- 深入JS物件的遍歷JS物件
- Java中如何遍歷Map物件的4種方法Java物件
- 在PHP中陣列遍歷的三種方法PHP陣列
- jQuery遍歷函式,javascript中的each遍歷jQuery函式JavaScript
- js遍歷多重json的方法JSON
- OC中陣列、字典的遍歷的三種方法陣列