当前位置: 首页 > news >正文

JavaScript中的循环特点和区别

一、前言:循环在 JS 中的核心地位

循环是编程的基础逻辑之一,在 JavaScript 中更是贯穿前端开发、Node.js 后端等所有场景 —— 从 DOM 遍历、数据处理到异步流程控制,几乎无处不在。但多数开发者仅停留在for/forEach的基础使用,忽略了不同循环的适用场景、性能差异和进阶技巧。本文将从基础语法到实战优化,全面拆解 JS 循环的核心知识点,帮你掌握 “什么时候用什么循环” 的底层逻辑。

二、JS 循环的 5 大核心类型:语法与基础用法

1. 传统循环:for/while/do...while

这是最基础的循环类型,兼容性覆盖所有浏览器(包括 IE),核心优势是完全可控(可中断、可跳过、可反向遍历)。

  • for循环:适合已知遍历次数的场景

// 正向遍历数组

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

for (let i = 0; i < arr.length; i++) {

console.log(arr[i]); // 1,2,3,4

}

// 反向遍历(性能更优,减少数组长度读取)

for (let i = arr.length - 1; i >= 0; i--) {

console.log(arr[i]); // 4,3,2,1

}

  • while循环:适合未知遍历次数的场景(需手动控制终止条件)

let count = 0;

while (count ) {

console.log(count); // 0,1,2

count++;

}

  • do...while循环:与while的区别是至少执行一次

let count = 3;

do {

console.log(count); // 3(即使条件不满足,仍执行一次)

count++;

} while (count );

2. 数组专用循环:forEach

ES5 引入的数组遍历方法,语法简洁,无需手动控制索引,但无法中断循环(break/return无效,return仅相当于跳过当前迭代)。

const arr = [1, 2, 3];

arr.forEach((item, index, array) => {

if (item === 2) return; // 跳过当前项,继续执行下一次

console.log(item); // 1,3

});

⚠️ 注意:forEach遍历稀疏数组时,会跳过空元素(与for循环不同)。

3. 迭代器循环:for...in/for...of

ES6 引入的新型循环,基于迭代器(Iterator)协议,适用于不同数据结构的遍历。

  • for...in:遍历对象的可枚举属性(包括原型链上的属性),不建议用于数组(会遍历数组的索引及自定义属性)。

const obj = { name: "张三", age: 20 };

for (const key in obj) {

// 过滤原型链属性

if (obj.hasOwnProperty(key)) {

console.log(`${key}: ${obj[key]}`); // name: 张三, age: 20

}

}

  • for...of:遍历可迭代对象(数组、字符串、Map、Set 等)的,支持break/continue/return中断循环,是数组遍历的优选方案。

// 遍历数组

const arr = [1, 2, 3];

for (const item of arr) {

if (item === 2) break; // 中断循环

console.log(item); // 1

}

// 遍历Map

const map = new Map([["name", "张三"], ["age", 20]]);

for (const [key, value] of map) {

console.log(`${key}: ${value}`); // name: 张三, age: 20

}

三、关键对比:不同循环的适用场景与性能

1. 功能对比表

循环类型

适用场景

能否中断

遍历空元素

遍历原型属性

for

数组、已知次数的遍历

-

while/do...while

未知次数的遍历

-

-

forEach

数组遍历(无需中断)

-

for...in

对象属性遍历

-

是(需过滤)

for...of

可迭代对象的值遍历

否(数组)

-

2. 性能分析(基于 Chrome 浏览器测试)
  • 性能排序(从快到慢):for(反向)> for(正向)> for...of > forEach > for...in
  • 核心原因:
    • for循环无额外函数调用和迭代器开销,直接操作索引,性能最优;
    • for...of基于迭代器,但底层优化较好,性能接近for;
    • forEach每次迭代需调用回调函数,存在函数调用开销;
    • for...in需遍历原型链属性,且需判断属性是否为自身所有,性能最差。

⚠️ 注意:性能差异仅在大数据量(10 万 + 条数据)下明显,日常开发中优先考虑代码可读性,无需过度优化。

四、进阶技巧:循环的高级用法与避坑指南

1. 中断循环的正确方式
  • 可中断循环:for/while/do...while/for...of(用break中断,continue跳过当前迭代);
  • 不可中断循环:forEach(需中断时,建议替换为for...of或for循环);
  • 替代方案:数组方法some/every(本质是遍历,但可通过return true中断):

const arr = [1, 2, 3];

// some:找到满足条件的项后中断,返回true

arr.some(item => {

if (item === 2) return true;

console.log(item); // 1

});

2. 异步循环的坑与解决方案

问题:forEach/for...in中使用异步操作(如setTimeout、接口请求)时,循环会先执行完,异步回调才触发,导致索引 / 值错乱。

// 错误示例:所有回调都打印4(i最终为4)

const arr = [1, 2, 3];

for (var i = 0; i < arr.length; i++) {

setTimeout(() => console.log(arr[i]), 0);

}

解决方案

  • 用let声明索引(块级作用域,每次迭代创建独立变量);
  • 用for...of(天然支持异步中断);
  • 用Promise.all(并行执行异步操作)。

// 正确示例:用for...of

const arr = [1, 2, 3];

async function asyncLoop() {

for (const item of arr) {

await new Promise(resolve => setTimeout(() => {

console.log(item); // 1,2,3(顺序执行)

resolve();

}, 1000));

}

}

asyncLoop();

3. 循环优化技巧
  • 数组遍历前缓存长度:`for (let i = 0, len = arr.length; i (避免每次迭代读取数组长度);
  • 反向遍历数组:减少数组索引边界判断(i >= 0比 `i 简单);
  • 大数据量遍历用for或for...of,避免forEach和for...in;
  • 遍历对象属性时,用Object.keys(obj).forEach替代for...in(避免原型链问题)。

五、实战场景:循环的最佳实践

  1. 场景 1:数组遍历并中断→ 用for...of或for循环;
  1. 场景 2:数组遍历无需中断,追求简洁→ 用forEach;
  1. 场景 3:对象属性遍历→ 用Object.keys(obj).forEach或for...in(需过滤原型链);
  1. 场景 4:Map/Set 遍历→ 用for...of;
  1. 场景 5:异步遍历(顺序执行)→ 用for...of+async/await;
  1. 场景 6:异步遍历(并行执行)→ 用Promise.all(arr.map(async item => {}))。

六、总结

JavaScript 循环的核心是 “选择合适的工具解决对应问题”:基础场景用for/forEach,对象遍历用Object.keys+forEach,可迭代对象用for...of,异步场景用for...of+async/await。掌握不同循环的语法、性能和适用场景,不仅能提升代码可读性,还能在大数据量场景下优化性能。

记住:没有最好的循环,只有最适合的循环。在实际开发中,需结合业务场景、代码可读性和性能需求综合选择。

http://www.jsqmd.com/news/76237/

相关文章:

  • Steamless工具:专业解除Steam游戏DRM限制
  • 千万不能错过!这款外卖点单小程序,让商家订单暴涨的秘密武器!
  • 如何快速修复GSE宏编译器在魔兽经典版中的问题:5步终极解决方案
  • Wan2.2-T2V-A14B模型在智能家居场景演示视频制作中的应用
  • 【Spring MVC适配篇】`HandlerAdapter` 核心适配器超深度解析:深入 `RequestMappingHandlerAdapter` 调用 `@Controller` 方法及复杂数
  • Wan2.1:重新定义视频创作边界的AI技术革命
  • NetAssistant网络调试工具终极指南:快速上手跨平台UDP/TCP调试
  • 一.AI前置知识了解
  • PyULog:无人机飞行日志数据解析与分析的完整解决方案
  • 2025年评价高的减速机/伺服行星减速机厂家最新推荐排行榜 - 品牌宣传支持者
  • 网页脚本加了debugger如何忽略
  • ConvNeXt模型部署实战:5个关键步骤解决预训练权重加载难题
  • SI2301S-ASEMI工业控制专用SI2301S
  • Go之路 - 7.go的函数
  • 当“印钞机”百度开始失血,是天灾还是人祸?
  • deepseek-r1大模型的本地部署
  • 5分钟快速上手:BDD100K数据集完整下载与训练指南
  • Linux上IO性能问题的故障排除实践
  • 网站怎么实现HTTPS访问?
  • 2025年竹纤维浴巾定制厂家推荐榜单:一次性浴巾‌/超细纤维浴巾‌/纯棉浴巾源头厂家精选 - 品牌推荐官
  • C++中指针,智能指针的理解
  • MySQL:Last_IO_Errno:“0“, Last_IO_Error:““, Last_SQL_Errno:“1950“
  • 分布式应用框架Microsoft Orleans - 4、掌握Microsoft Orleans状态管理:从持久化配置到事务处理
  • 基于SSM+Vue的实习管理系统的设计与实现
  • 2025年12月铝合金母线槽,接插式母线槽,高压母线槽厂商推荐:导电效率+安装便捷度实测​ - 品牌鉴赏师
  • Wan2.2-T2V-A14B模型生成视频的元数据嵌入与追踪
  • 掌握OptiSystem的5大实战技巧:从零开始的光通信仿真指南
  • 3步掌控Mac性能:AppPolice让你的电脑告别卡顿烦恼
  • 分布式应用框架Microsoft Orleans - 2、动手实践:构建你的第一个Microsoft Orleans应用程序
  • Wan2.2-T2V-A14B能否理解‘情绪’类抽象描述?实验来了