JavaScript 循环

循环是 JavaScript 中处理重复逻辑的核心语法,也是前端开发中最常使用的基础能力之一。从简单的数组遍历到复杂的异步任务处理,不同场景下选择合适的循环方式,既能提升代码可读性,也能优化执行效率。本文将从基础到进阶,全面拆解 JS 循环的类型、用法、场景选型和性能优化,帮你彻底掌握这一核心知识点。

一、循环的核心价值

在编程中,当需要对一组数据执行相同操作(如遍历数组、计算总和、筛选数据),或重复执行某段逻辑直到满足条件时,循环可以避免重复编写冗余代码,实现:

  • 批量处理数据(如数组遍历、对象属性操作);
  • 条件性重复执行(如累加计算、轮询接口);
  • 自动化逻辑(如生成 DOM 列表、数据格式化)。

二、JS 循环的分类与基础用法

JS 中的循环主要分为两大阵营:传统基础循环 (手动控制迭代)和现代迭代器循环(语义化遍历),下面逐一拆解。

2.1 传统基础循环:手动掌控每一步

这类循环需要开发者手动定义初始化、循环条件和迭代规则,可控性最强,适合已知循环次数或需要精细控制的场景。

(1)for 循环:结构化最强的循环

语法

javascript

运行

复制代码
for (初始化表达式; 条件表达式; 更新表达式) {
  // 循环体:条件为true时执行
}

核心场景:遍历数组(性能最优)

javascript

运行

复制代码
const arr = [10, 20, 30, 40];
// 正向遍历
for (let i = 0; i < arr.length; i++) {
  console.log(`索引${i}的值:${arr[i]}`);
}

// 反向遍历(性能略优,减少length查询次数)
for (let i = arr.length - 1; i >= 0; i--) {
  console.log(arr[i]);
}

// 优化:缓存length(大数据遍历推荐)
for (let i = 0, len = arr.length; i < len; i++) {
  // 避免每次循环都查询arr.length
}

关键特性

  • 支持break(终止循环)、continue(跳过当前轮次);
  • 可手动控制索引,适合需要操作索引的场景(如数组切片、替换元素);
  • 大数据遍历性能最优,无额外语法开销。
(2)while 循环:未知次数的循环

先判断条件,再执行循环体,适合循环次数不确定的场景。

语法与示例:累加至和大于 100

javascript

运行

复制代码
let sum = 0;
let num = 1;
// 条件满足时持续执行
while (sum <= 100) {
  sum += num;
  num++;
}
console.log(sum); // 105(1+2+...+14)
(3)do...while 循环:至少执行一次的循环

while的核心区别是先执行循环体,再判断条件,保证循环至少执行一次。

示例:用户输入验证

javascript

运行

复制代码
let input;
do {
  input = prompt('请输入数字:');
} while (isNaN(Number(input))); // 输入非数字则重复提示
console.log('输入的数字是:', input);

2.2 现代迭代器循环:语义化遍历

ES5 + 新增的迭代器循环,无需手动控制索引,语法更简洁,语义化更强,是日常开发的首选。

(1)for...in:遍历对象属性

专门用于遍历对象的可枚举属性(包括原型链上的属性),也可遍历数组,但不推荐(索引为字符串类型)。

核心用法:安全遍历对象

javascript

运行

复制代码
const user = { name: '张三', age: 20, gender: '男' };
for (const key in user) {
  // 过滤原型链属性(必须!避免遍历继承的属性)
  if (user.hasOwnProperty(key)) {
    console.log(`${key}: ${user[key]}`);
  }
}
// 输出:
// name: 张三
// age: 20
// gender: 男

避坑提醒

  • 遍历数组时,key是字符串(如 "0"),可能导致+key等操作出错;
  • 遍历顺序不固定,不适合依赖顺序的场景。
(2)for...of:遍历可迭代对象

ES6 新增的for...of数组遍历的首选,可遍历所有可迭代对象(数组、字符串、Set、Map、Generator 等),兼顾语义化和可控性。

核心用法

javascript

运行

复制代码
// 遍历数组
const arr = [1, 2, 3];
for (const item of arr) {
  if (item === 2) break; // 支持break/continue
  console.log(item); // 1
}

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

// 遍历Map(键值对)
const map = new Map([['name', '李四'], ['age', 25]]);
for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}

// 结合entries获取数组索引+值
for (const [index, item] of arr.entries()) {
  console.log(`索引${index}:${item}`);
}

核心优势

  • 支持break/continue/return中断循环;
  • 直接获取元素值,无需操作索引;
  • 不遍历原型链,无需额外过滤。

2.3 数组专用迭代方法:函数式编程首选

ES5 为数组提供了一系列专用迭代方法,语义化极强,适合函数式编程,无需关心迭代细节,专注业务逻辑。

方法 核心作用 返回值 是否修改原数组
forEach 遍历数组,执行回调 无(undefined)
map 遍历数组,返回处理后的新数组 新数组
filter 筛选符合条件的元素,返回新数组 新数组
some 判断是否至少一个元素满足条件 布尔值
every 判断是否所有元素满足条件 布尔值
find 查找第一个满足条件的元素 元素 /undefined
reduce 聚合数组,生成单个值(累加 / 拼接) 任意类型(自定义)

实战示例

javascript

运行

复制代码
const nums = [1, 2, 3, 4, 5];

// 1. forEach:简单遍历
nums.forEach((item, index) => {
  console.log(`第${index+1}个元素:${item}`);
});

// 2. map:数据转换(如所有数乘2)
const doubleNums = nums.map(item => item * 2);
console.log(doubleNums); // [2, 4, 6, 8, 10]

// 3. filter:筛选偶数
const evenNums = nums.filter(item => item % 2 === 0);
console.log(evenNums); // [2, 4]

// 4. reduce:数组求和(初始值为0)
const sum = nums.reduce((total, current) => total + current, 0);
console.log(sum); // 15

// 5. some:判断是否有大于3的数
const hasBigNum = nums.some(item => item > 3);
console.log(hasBigNum); // true

注意forEach/map等方法无法用 break/continue 中断 ,若需中断循环,建议改用for...of或普通for循环。

三、循环的中断与跳过

不同循环的中断方式不同,整理如下:

关键字 作用 适用循环类型
break 终止整个循环 for/while/do...while/for...of
continue 跳过当前轮次,进入下一轮 for/while/do...while/for...of
return 终止函数(含内部循环) 所有循环(函数内)

示例:中断循环

javascript

运行

复制代码
// break终止for...of循环
const arr = [1, 2, 3, 4];
for (const item of arr) {
  if (item === 3) break;
  console.log(item); // 1, 2
}

// continue跳过当前轮次
for (let i = 0; i < 5; i++) {
  if (i === 2) continue;
  console.log(i); // 0, 1, 3, 4
}

四、循环选型指南:不同场景怎么选?

场景 推荐循环方式 原因
遍历数组(需中断 / 高性能) 普通 for 循环 /for...of 可控性强、性能优
遍历数组(函数式 / 无中断) forEach/map/filter/reduce 语义化强、代码简洁
遍历对象属性 for...in + hasOwnProperty 专门遍历对象,过滤原型链属性
遍历 Set/Map for...of 原生支持可迭代对象
未知循环次数(条件循环) while/do...while 无需提前定义次数
异步循环(如接口请求) for...of + async/await 支持异步中断,避免回调地狱

异步循环示例(for...of + async/await)

javascript

运行

复制代码
// 模拟异步请求
const fetchData = (id) => {
  return new Promise(resolve => {
    setTimeout(() => resolve(`数据${id}`), 1000);
  });
};

// 异步遍历数组,按顺序请求
const asyncLoop = async () => {
  const ids = [1, 2, 3];
  for (const id of ids) {
    const data = await fetchData(id);
    console.log(data); // 依次输出:数据1、数据2、数据3
  }
};
asyncLoop();

五、循环性能优化技巧

  1. 缓存数组长度 :遍历大数据数组时,将arr.length缓存到变量,避免每次循环查询(普通 for 循环适用);

    javascript

    运行

    复制代码
    // 优化前
    for (let i = 0; i < arr.length; i++) {}
    // 优化后
    for (let i = 0, len = arr.length; i < len; i++) {}
  2. 减少循环内操作:避免在循环体中定义函数、创建对象等耗时操作,尽量移到循环外;

  3. 优先使用原生方法map/filter等原生方法由引擎优化,性能优于手动遍历;

  4. 避免死循环 :确保循环条件最终会变为false(如迭代变量要递增 / 递减);

  5. 大数据遍历用普通 for:普通 for 循环无额外语法开销,性能 > for...of > forEach。

六、常见坑点避坑

  1. for...in 遍历数组 :索引是字符串类型,易导致arr[key + 1]等操作出错,坚决避免;

  2. forEach 无法中断:若需中断,不要用 forEach,改用 for...of;

  3. var 声明迭代变量 :for 循环中用 var 声明 i 会导致变量提升,建议用 let;

    javascript

    运行

    复制代码
    // 错误示例:var声明导致所有回调共用一个i
    for (var i = 0; i < 3; i++) {
      setTimeout(() => console.log(i), 100); // 输出3,3,3
    }
    // 正确示例:let声明,每个循环独立i
    for (let i = 0; i < 3; i++) {
      setTimeout(() => console.log(i), 100); // 输出0,1,2
    }
  4. 循环中修改原数组 :遍历数组时直接修改元素(如arr[i] = xxx)可能导致遍历异常,建议先拷贝数组。

总结

  1. JS 循环分为传统基础循环(for/while/do...while)和现代迭代器循环(for...in/for...of/ 数组方法),核心是根据场景选择合适的类型;
  2. 遍历数组优先用 for...of(语义化)或普通 for(高性能),遍历对象用 for...in+hasOwnProperty;
  3. 数组专用方法(map/filter/reduce)适合函数式编程,但无法中断循环;异步循环优先用 for...of+async/await。

掌握循环的核心逻辑和选型技巧,能让你的代码既简洁又高效。如果需要针对 "嵌套循环优化""无限循环排查" 等进阶场景深入讲解,可以留言补充。

👉 **觉得有用的点点关注谢谢~**

相关推荐
guygg882 小时前
5G PDSCH信道吞吐量MATLAB仿真实现(含信道生成与解调)
开发语言·5g·matlab
傻乐u兔2 小时前
C语音初阶————调试实用技巧2
c语言·开发语言
沛沛老爹3 小时前
从Web到AI:行业专属Agent Skills生态系统技术演进实战
java·开发语言·前端·vue.js·人工智能·rag·企业转型
程农3 小时前
基于Java的报名系统
java·开发语言
yugi9878383 小时前
基于字典缩放的属性散射中心参数提取MATLAB仿真程序
开发语言·matlab
yanyu-yaya4 小时前
速学兼复习之vue3章节3
前端·javascript·vue.js·学习·前端框架
林恒smileZAZ4 小时前
前端拖拽,看似简单,其实处处是坑
前端·javascript·vue.js
小白学大数据4 小时前
绕过拼多多 App 反抓包机制的综合逆向解决方案
开发语言·爬虫·python·自动化