忙了好一段時間,項目上線後終於有那麼一點點空檔期靜下來整理一些問題了。當咱們在開發項目的時候,用到遍歷的地方確定少不了,那麼咱們有那麼多的遍歷方法,在不一樣狀況下用那種方法會更優雅並且還沒bug呢?android
首先,我在這裏先列出幾種常見的遍歷機制,而後針對部分來作一個我對它的理解,有不一樣見解的老鐵也能夠分享一下,下面是我列出來的幾種遍歷的方法,另外咱們經常使用來中斷循環的語句我在這裏簡單的提一下:es6
a、continue: 中斷本次循環;express
b、return和break直接跳出循環。數組
// for 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的遍歷機制裏是不支持中斷遍歷的,而後我只能尋求其餘的解決方案了。緩存
下面我在這對上述列舉的遍歷方法逐個逐個的分析一下,有些分析不到位的,或者有不一樣的見解的老鐵們請分享你的見解:curl
1. 普通的for循環ide
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 };
一、 這是最簡潔、最直接的遍歷數組元素的語法
二、 這個方法避開了for-in循環的全部缺陷
三、 與forEach()不一樣的是,它能夠正確響應break、continue和return語句
四、性能要好於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() 方法會依次執行數組的每一個元素:
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() 方法使用指定函數檢測數組中的全部元素:
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循環解決了這個問題。
換了一種遍歷方法後,這個問題就解決了,在這裏簡單的作了一些開發時遇到的坑作了一些總結,有不一樣見解的各路大神,跪求分享!!!