简单了解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
};

最简单的一种,正常用的话也不会出现什么问题,想中断也可以中断,性能上也还可以。

image

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来中断循环,如下图所示:

image

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循环

image

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的时候,要考虑使用场景了。

image

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。
image

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。
image

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值,建议不要用该方法来遍历数组,因为它的效率是最低的。

image

9. filter()

var arr = [1, 2, 3];
arr.filter(item => { // item为数组当前的元素
    return item > 1; // [2, 3]
});

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

image

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

image

上述简单的介绍了各种遍历的方法。

在前面我有提到一个苹果手机遍历出现数据重复的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));
image
image

我们看一下安卓手机和苹果手机alert出来的数据有什么区别:在截图中我们就可以发现,苹果手机整体遍历了2轮,这样个结果是不是很诡异?是的我也觉得很诡异,怎么来解决呢,很多很学会想到一些方法,比如用数组去重的方法,并且es6的去重方法很优雅(var newArr = Array.from(new Set(subFormData))),或者其他去重的方法,这样做并没有什么不好,比较方法有千千万,喜欢就好。当时因为考虑到里面的逻辑问题,我就直接改了一行代码,用了最普通的方法,因为性能上会有优势,所以我就用了普通的for循环解决了这个问题。

image

换了一种遍历方法后,这个问题就解决了,在这里简单的做了一些开发时遇到的坑做了一些总结,有不同看法的各路大神,跪求分享!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容