下班前几分钟,我彻底弄懂了这5种for循环的差异

arr.forEach(item => {

console.log(item); // 直接输出了数组的元素 1 2 3 4 5

});

// 遍历对象

let obj = {name:“leo”, age:20, country:“China”};

let keys = Object.keys(obj);

keys.forEach(i => {

console.log(i); // 对象的键值 name age country

console.log(obj[i]); // 对象的键对应的值 leo 20 China

});

3、map

map 是ES5版本发布的,遍历时可以返回一个新数组,新数组的结果是原数组中的每个元素都调用一次提供的函数后的返回值。

let arr = [1,2,3,4,5];

let newArr = arr.map(i => i * i);

console.log(newArr); // [1, 4, 9, 16, 25]

4、for in

for in 是ES5版本发布的,以随机顺序遍历一个对象中除 Symbol 以外的可枚举属性(包括原型对象上的可枚举属性)。

// 遍历数组

let arr = [1,2,3,4,5];

for(let i in arr){

console.log(i); // 索引,数组下标 0 1 2 3 4

console.log(arr[i]); // 数组下标所对应的元素 1 2 3 4 5

}

// 遍历对象

let obj = {name:“leo”, age:20, country:“China”};

for(let key in obj){

console.log(key); // 对象的键 name age country

console.log(obj[key]); // 对象的键对应的值 leo 20 China

}

// 遍历字符串

let str = “abcdef”;

for(let i in str){

console.log(i); // 索引,字符串下标 0 1 2 3 4 5

console.log(str[i]); // 字符串下标所对应的元素 a b c d e f

}

5、for of

for of 是ES6版本发布的,在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

// 迭代数组

let arr = [1,2,3,4,5];

for(let item of arr){

console.log(item); // 遍历数组元素 1 2 3 4 5

}

// 迭代字符串

let str = “abcdef”;

for(let item of str) {

console.log(item); // 遍历字符串元素 a b c d e f

}

// 迭代Map

let iterable = new Map([[“a”, 1], [“b”, 2], [“c”, 3]]);

for (let entry of iterable) {

console.log(entry); // 遍历Map中可迭代元素 [“a”, 1] [“b”, 2] [“c”, 3]

}

// 迭代Set

let iterable = new Set([1, 1, 2, 2, 3, 3,4]);

for (let value of iterable) {

console.log(value); // 遍历Set中可迭代元素 1 2 3 4

}

// 迭代arguments类数组对象

function fn(){

for (let argument of arguments) {

console.log(argument);

}

}

fn(1, 2, 3); // 1 2 3

二、使用差异


1、场景差异

  • 普通for循环 是最原始的循环语句。定义一个变量 i(数字类型,表示数组的下标),按照一定的条件,对 i 进行循环累加。条件通常为循环数组的长度,当超过长度就停止循环。因为对象无法判断长度,所以通常搭配 Object.keys() 使用。

  • forEach 一般认为是 普通for循环 的加强版,可以发现它比 普通for循环 在写法上简单了不少,但是本质上也是数组的循环。每个数组元素执行一次回调函数,不改变原数组,返回值是 undefined。

  • map 给原数组中的每个元素都按顺序调用一次回调函数,返回一个新数组,不改变调用它的原数组本身。

  • for in 遍历对象上的可枚举属性,包括原型对象上的属性,且按任意顺序进行遍历,即顺序不固定。遍历数组时把数组的下标当作键值,此时的 i 是个字符串型的。它是为遍历对象属性而构建的,不建议与数组一起使用。

  • for of 用于遍历可迭代对象的数据。

2、能力差异

作为一个使用者,仅仅认识它们是不够的,在实际开发中鉴别他们的优缺点,因地制宜地使用它们,扬长避短,可以提高程序的整体性能。

关于跳出循环体

在循环中满足一定条件就跳出循环体,或者跳过不符合条件的数据继续循环其它数据,是经常会遇到的需求。常用的语句是 break、return。

**注意:**forEach 和 map 不支持跳出循环体,其它三种方法均支持。

**原理:**查看 forEach 实现原理,就会理解这个问题。

Array.prototype.forEach(callbackfn [,thisArg]{

})

传入的 function 是这里的回调函数。在回调函数里面使用 break 肯定是非法的,因为 break 只能用于跳出循环,回调函数不是循环体。

在回调函数中使用 return,只是将结果返回到上级函数,而恰巧还在这个 for循环 中,并没有结束 for循环,所以 return 也是无效的。

关于遍历的属性

for in 会遍历出原型对象上的属性。

Object.prototype.objCustom = function() {};

Array.prototype.arrCustom = function() {};

let arr = [‘a’, ‘b’, ‘c’];

arr.foo = ‘hello’;

for(let i in arr){

console.log(i); // 会遍历出原型对象上的属性 0 1 2 foo arrCustom objCustom

}

然而在实际的开发中,我们并不需要原型对象上的属性。这种情况下我们可以使用hasOwnProperty() 方法,它返回一个布尔值,判断对象本身是否具有指定的属性。

Object.prototype.objCustom = function() {};

Array.prototype.arrCustom = function() {};

let arr = [‘a’, ‘b’, ‘c’];

arr.foo = ‘hello’;

for(let i in arr){

if(arr.hasOwnProperty(i)){

console.log(i); // 0 1 2 foo

}

}

// 可见数组本身的属性还是无法摆脱,此时建议使用 forEach

对于纯对象的遍历,选择 for in 枚举更方便;对于数组遍历,如果不需要知道索引,使用 for of 迭代更合适,还可以实现中断;如果需要知道索引,则 forEach 更合适;对于其他字符串,类数组,类型数组的迭代,for of 则是更胜一筹,但是请注意低版本浏览器的适配性。

三、性能比较


在测试环境、测试数据等条件一致的情况下,性能排序基本为:

for > for of > forEach > map > for in

1、普通for循环 当然是最快的,因为它没有任何额外的函数调用栈和上下文。

2、for of 是具有 Iterator 接口的数据结构,都可以使用它来迭代成员。它直接读取的是键值。

3、forEach 其实比我们想象得要复杂一些,它实际上是 array.forEach(function(currentValue, index, arr), thisValue),它不是普通的 for循环 语法糖,还有诸多参数和上下文需要在执行的时候考虑进来,因此会拖慢性能。

4、map 随其后,因为它的返回值是一个等长的全新数组,数组创建和赋值产生的性能开销较大。

5、for in 性能最差,因为它需要穷举对象的所有属性,包括自身存在的、自定义添加的、以及原型对象上的,都会遍历到,且 key 是 String 类型,有转换过程,开销比较大。

四、使用建议


在实际开发中我们应该结合语义化、可读性和程序性能,去选择究竟使用哪种方案。

1、如果你需要将数组按照某种规则映射成为另一个数组,推荐使用 map。

2、如果你需要进行简单的遍历,可以用for、forEach 或者 for of。

3、如果你需要对一个纯对象进行遍历,推荐使用 for in。

最后

在面试前我花了三个月时间刷了很多大厂面试题,最近做了一个整理并分类,主要内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

  • HTML5新特性,语义化

  • 浏览器的标准模式和怪异模式

  • xhtml和html的区别

  • 使用data-的好处

  • meta标签

  • canvas

  • HTML废弃的标签

  • IE6 bug,和一些定位写法

  • css js放置位置和原因

  • 什么是渐进式渲染

  • html模板语言

  • meta viewport原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值