还在用for循环?这些隐藏的性能坑你可能踩过!

你是不是也遇到过这种情况:页面数据一多,滚动起来就卡成PPT?明明代码写得没问题,但用户总抱怨应用太慢?

很多时候,问题就出在最基础的循环上!今天我就带你彻底搞懂JavaScript中的各种循环,帮你避开那些看不见的性能大坑。

读完本文,你会掌握各种循环的适用场景,学会如何选择最高效的遍历方式,让你的应用性能瞬间提升一个档次!

先来看看最熟悉的for循环

for循环是我们最早接触的循环方式,也是最基础、最灵活的。

// 最传统的for循环
for (let i = 0; i < array.length; i++) {
  console.log(array[i]); // 逐个打印数组元素
}

这里有个小细节要注意:每次循环都会读取array.length,如果数组长度不变,最好先缓存起来。

// 优化版:缓存数组长度
for (let i = 0, len = array.length; i < len; i++) {
  console.log(array[i]); // 性能更好一些
}

for循环最大的优点就是可控性强,你可以随时用break跳出或者continue跳过当前循环。

while和do-while怎么选?

while是先判断再执行,do-while是先执行再判断。

// while循环:可能一次都不执行
let i = 0;
while (i < 5) {
  console.log(i); // 打印0到4
  i++;
}

// do-while循环:至少执行一次
let j = 0;
do {
  console.log(j); // 即使条件不成立也会执行一次
  j++;
} while (j < 5);

do-while适合那些至少要执行一次的场景,比如读取用户输入直到正确为止。

数组遍历的现代方式:forEach

forEach是数组特有的方法,写起来更简洁。

const fruits = ['苹果', '香蕉', '橙子'];

fruits.forEach(function(fruit, index) {
  console.log(index + ': ' + fruit); // 输出"0: 苹果"等
});

用箭头函数写更简洁:

fruits.forEach((fruit, index) => {
  console.log(`${index}: ${fruit}`); // 使用模板字符串
});

但是注意:forEach不能用break中断循环,也不能用continue跳过当前项。如果需要中途退出,还得用传统的for循环。

for…of循环:ES6的新选择

for…of是ES6引入的,可以遍历任何可迭代对象。

// 遍历数组
const numbers = [1, 2, 3];
for (const num of numbers) {
  console.log(num); // 1, 2, 3
}

// 遍历字符串
const str = 'hello';
for (const char of str) {
  console.log(char); // 'h', 'e', 'l', 'l', 'o'
}

for…of的优点是可以直接获取值,不需要通过索引,而且支持break和continue。

性能大比拼:谁才是真正的速度之王?

说了这么多,到底哪种循环最快呢?我们来做个测试。

先创建一个包含100万个元素的数组:

const bigArray = new Array(1000000).fill().map(() => Math.random());

然后分别测试各种循环的耗时:

// 测试for循环
console.time('for循环');
for (let i = 0, len = bigArray.length; i < len; i++) {
  // 什么都不做,只是遍历
}
console.timeEnd('for循环');

// 测试forEach
console.time('forEach');
bigArray.forEach(item => {
  // 什么都不做
});
console.timeEnd('forEach');

// 测试for...of
console.time('for...of');
for (const item of bigArray) {
  // 什么都不做
}
console.timeEnd('for...of');

在我的电脑上测试结果是这样的:

  • for循环:约5ms
  • forEach:约15ms
  • for…of:约30ms

传统for循环完胜!forEach大概是for循环的3倍时间,for…of则是6倍左右。

为什么性能差这么多?

其实原因很简单:

  • for循环是最底层的实现,直接通过索引访问,没有额外开销
  • forEach是函数调用,每次迭代都要执行一次回调函数,有函数调用的开销
  • for…of需要创建一个迭代器对象,也有额外的开销

但是!先别急着把所有循环都改成for循环。

实际开发中该怎么选?

性能测试只是理论值,实际开发中还要考虑代码可读性和维护性。

什么时候用for循环:

  • 需要高性能遍历大数据量时
  • 需要中途break或continue时
  • 需要同时操作多个数组时

什么时候用forEach:

  • 代码简洁性比极致性能更重要时
  • 不需要中断循环时
  • 链式调用数组方法时

什么时候用for…of:

  • 遍历非数组的可迭代对象时(如Set、Map)
  • 需要break/continue但又想写简洁代码时

简单来说就是:

  • 要性能选for
  • 要简洁选forEach
  • 要通用选for…of

一些实用的小技巧

用break提前退出循环:

for (let i = 0; i < array.length; i++) {
  if (array[i] === '目标值') {
    console.log('找到了!');
    break; // 找到后就退出循环
  }
}

用continue跳过本次循环:

for (let i = 0; i < array.length; i++) {
  if (array[i] % 2 === 0) {
    continue; // 跳过偶数
  }
  console.log(array[i]); // 只打印奇数
}

循环嵌套的性能优化:

// 不好的写法:内层循环每次都要计算长度
for (let i = 0; i < outerArray.length; i++) {
  for (let j = 0; j < innerArray.length; j++) {
    // 每次都要读取innerArray.length
  }
}

// 优化写法:缓存内层数组长度
for (let i = 0, outerLen = outerArray.length; i < outerLen; i++) {
  for (let j = 0, innerLen = innerArray.length; j < innerLen; j++) {
    // 性能更好
  }
}

总结一下

今天我们把JavaScript中的循环彻底讲透了。记住这几个要点:

  1. for循环性能最好,适合处理大数据量
  2. forEach写起来最简洁,但性能稍差
  3. for…of最通用,但性能最差
  4. 实际开发中要在性能和可读性之间权衡

不要盲目追求性能而牺牲代码可读性,除非你确实在处理海量数据。大多数情况下,代码的可维护性比那几毫秒的性能提升更重要。

对了,你平时最喜欢用哪种循环?有没有因为循环性能问题踩过坑?欢迎在评论区分享你的经历!

原文链接:https://mp.weixin.qq.com/s/AYapL2QYJXdcIPBzVgybMA

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值