循环的理解,for、forEach...

js中的循环,for、for...in、for...of、forEach,循环的语法大都大同小异,参考文献,探讨记录一下for循环和forEach的差异;

for循环和forEach循环的本质、语法、性能区别;

forEach和for循环的本质区别

for循环是在js提出的时候就存在的循环方法,forEach是ES5中就提出的,可以挂载在迭代对象原型上的方法,比如,Array,Set,Map,forEach是一个迭代器,负责遍历可以迭代的对象;

Java中,forEach循环也叫做增强版for循环,forEach在java中的书写格式,for(元素类型 元素名称:遍历数组/集合/能迭代的){语句}。

Java中,forEach虽然是for循环的简化版本,但并不代表就比for循环好用,forEach适用于循环次数未知,或者计算循环次数比较麻烦的情况下使用效率更高,但是更为复杂的一些循环还是需要用到for循环效率更高。

遍历,迭代,可迭代的对象分别是什么

  • 遍历:指的是对数据结构的每一个成员进行有规律的且为一次的访问行为;
  • 迭代:迭代是递归的一种特殊形式,是迭代器提供的一种方法,默认情况下是按照一定的顺序逐个访问数据结构成员,迭代也是一种遍历行为
  • 可迭代对象:ES6中引入了iterable类型,Array、Set、Map、String、arguments、NodeList都属于iterable,他们特点就是都拥有[symbol.iterable]方法,包含他的对象都认为是可迭代的iterable;

forEach实际上就是一个迭代器,它与for循环本质上的就是forEach是负责遍历(Array、Set、Map)这些可迭代对象的,而for循环是一种循环机制,只是能通过它来遍历出数组;

迭代器

迭代器设计一种特殊对象,ES6规范中它的标志是返回对象的next()方法,迭代行为判断在done中,在不暴露内部表示的情况下,迭代器实现了遍历

只要是可迭代对象,调用内部的Symbol.iterator都会提供一个迭代器,并根据迭代器返回的next方法类访问内部,这也是for...of的实现原理;

let array = [1,2,3,4];
for (const item of array) {
    console.log(item); // 1 2 3 4
}

 把调用的next方法返回对象的value值保存在item中,直到value为undefind跳出循环,所有可迭代的对象可供for...of消费。

可迭代对象中的Symbol.iterator属性被调用时都能生成迭代器,而forEach也是生成一个迭代器,在内部的回调函数中传递出每个元素的值。


forEach和for循环的语法区别

了解两者之间的区别

例如forEach的参数

1、forEach的中断

2、forEach删除自身元素

3、index不可被充值

4、for循环可以控制循环的起点。

forEach的传参:

array.forEach((self,index,array) => {},this)

self:数组当前遍历的元素,默认从左往右依次获取数组元素;

index:数组当前元素的索引,第一个索引为0,依次类推;

array:当前遍历的数组;

this:回调函数中this的指向;

利用数组array去重 =>

let arr1 = [1,2,1,3,1,2];
let arr2 = [];
arr1.forEach(function (self,index,arr) {
    arr.indexOf(self) === index ? arr2.push(self) : null;
});
console.log(arr2); // [1,2,3]

forEach的中断

js中会有break、return、continue对函数进行中断或者跳出循环的操作,在for循环中会用到一些中断行为,这对于优化数组的遍历查找是很友好的,但是由于forEach属于迭代器,只能按序依次遍历完成,所以forEach不支持中断行为

let arr = [1, 2, 3, 4],
    i = 0,
    length = arr.length;
for (; i < length; i++) {
    console.log(arr[i]); //1,2
    if (arr[i] === 2) {
        break;
    };
};

arr.forEach((self,index) => {
    console.log(self);
    if (self === 2) {
        break; //报错
    };
});

arr.forEach((self,index) => {
    console.log(self);
    if (self === 2) {
        continue; //报错
    };
});

但是如果一定要在forEach中跳出循环,可以借助try/catch

try {
    var arr = [1, 2, 3, 4];
    arr.forEach(function (item, index) {
        //跳出条件
        if (item === 3) {
            throw new Error("LoopTerminates");
        }
        //do something
        console.log(item);
    });
} catch (e) {
    if (e.message !== "LoopTerminates") throw e;
};

若遇到return,并不会报错,但是不会生效;

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

function find(array, num) {   
    array.forEach((self, index) => {       
        if (self === num) {     
            return index;      
        };   
    });
};
let index = find(arr, 2);// undefined

forEach删除自身元素,index不可被重置

forEach中无法控制index的值,forEach只会依次自增直至大于数组的length跳出循环,所以无法删除自身进行index重置;

index不会随着函数体内部对它的增减而发生变化,在实际开发中,遍历数组同时删除某项的操作也很常见,因此在使用forEach删除的时候需要注意;

let arr = [1,2,3,4]
arr.forEach((item, index) => {  
    console.log(item); // 1 2 3 4  
    index++;
});

for循环可以控制循环的起点

上面提到的forEach的循环起点只能为0不能进行人为干预,而for循环不一样,可以自定义循环的起点;

let arr = [1, 2, 3, 4],
    i = 1,
    length = arr.length;

for (; i < length; i++) {
    console.log(arr[i]) // 2 3 4
};

这样之前数组遍历并删除自身的操作就可以完成了

let arr = [1, 2, 1],
    i = 0,
    length = arr.length;

for (; i < length; i++) {
    // 删除数组中所有的1
    if (arr[i] === 1) {
        arr.splice(i, 1);
        //重置i,否则i会跳一位
        i--;
    };
};
console.log(arr); // [2]
//等价于
var arr1 = arr.filter(index => index !== 1);
console.log(arr1) // [2]

for循环与forEach的性能方面

参考各路大神以及测试实验,for、forEach、Map的性能在浏览器环境中的性能的不一样;

性能对比:for > forEach > map,for循环比forEach快一倍,forEach比map快20%左右。

原因分析:

for:for循环没有额外的函数调用栈和上下文,所以它的实现最为简单;

forEach:对于forEach来说,它的函数签名中包含了参数和上下文,所以性能会低于for循环;

map:之所以map会最慢是因为map会返回一个新的数组,数组的创建和复制会分配内存空间,因此会带来比较大的性能开销;

因此,如果将map套入一个循环中,就会带来更多不必要的内存消耗,当大家使用迭代器遍历一个数组的时候,如果不需要返回一个新数组却使用map是不可取的。


对于性能的相关分析,可能还需要从更多的方向去测试解析,比如迭代器、生成器等多方面去分析才行...

前面提到for...of,这里也提一下js中for...in。

for...of,forEach,for...in的区别

forEach

forEach方法没办法使用break语句跳出循环,或者使用return从函数体内返回;

objArr.forEach(function (value) {
    console.log(value);
})

for-in

index值会是字符串(String)类型

循环不仅会遍历数组元素,还会遍历任意其他自定义添加的属性,比如,objArr上面包含的自定义属性,objArr.name,那这次循环也会出现此name属性

某些情况下,以下代码会随机顺序循环数组

for-in的使用,是给普通的以字符串的值为key的对象使用的,而非数组

for(var index in objArr){
	console.log(objArr[index])
}

for-of

可以避免所有for-in循环的陷阱

不同于forEach,可以使用break、continue和return中断循环

for-of循环不仅仅支持数组的遍历,也适用于很多类似数组的对象,也支持字符串的遍历

for-of不适用于处理原生的原生对象

for(let value of objArr){
	console.log(value)
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sinder_小德

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值