Skip to content

循环

循环用于重复执行一段逻辑。JavaScript 中常见的循环方式包括:

  • while
  • do...while
  • for
  • for...in
  • for...of

什么时候需要循环

循环通常用于:

  • 遍历数组、对象、集合
  • 重复执行某个任务直到满足条件
  • 批量处理一组数据

while

while 适合“只要条件成立就持续执行”的场景。

js
let count = 3

while (count > 0) {
  console.log(count)
  count--
}

它的特点是先判断条件,再决定是否执行循环体。

do...while

do...while 会先执行一次,再判断条件。

js
let count = 0

do {
  console.log(count)
  count--
} while (count > 0)

这种写法不算高频,但在“循环体至少要执行一次”的场景里很直接。

for

for 是最常见的循环形式,适合计数式循环。

js
for (let i = 0; i < 3; i++) {
  console.log(i)
}

这三个部分分别表示:

  • 初始化
  • 继续条件
  • 每轮结束后的更新动作

变量作用域

js
for (let i = 0; i < 3; i++) {
  console.log(i)
}

// console.log(i) // i is not defined

如果使用 let 声明循环变量,它只在当前循环块内有效。

breakcontinue

break

break 用于提前结束整个循环:

js
for (let i = 0; i < 10; i++) {
  if (i === 5) {
    break
  }

  console.log(i)
}

continue

continue 用于跳过当前这一轮,直接进入下一轮:

js
for (let i = 0; i < 6; i++) {
  if (i % 2 === 0) {
    continue
  }

  console.log(i)
}

这类写法常用于过滤不需要处理的项。

for...in

for...in 用于遍历对象的可枚举属性名。

js
const user = {
  name: 'Lee',
  age: 18,
}

for (const key in user) {
  console.log(key, user[key])
}

它拿到的是“键”,不是值。

适合场景

  • 遍历普通对象属性
  • 需要按键名读取值

注意点

如果只是想处理对象自己的键,很多时候 Object.keys()Object.entries() 会更直观。

for...of

for...of 用于遍历可迭代对象的值,例如:

  • 数组
  • 字符串
  • Set
  • Map
js
const list = [10, 20, 30]

for (const item of list) {
  console.log(item)
}

它拿到的是“值”,不是键。

for...infor...of 的区别

for...in 遍历键名

遍历键名:

js
const arr = ['a', 'b']

for (const key in arr) {
  console.log(key) // 0 1
}

for...of 遍历值

遍历值:

js
const arr = ['a', 'b']

for (const value of arr) {
  console.log(value) // a b
}

日常开发里:

  • 遍历对象属性,优先考虑 for...inObject.keys
  • 遍历数组内容,优先考虑 for...of

标签语句

在多层嵌套循环中,有时需要直接跳出外层循环,可以配合标签使用 break

js
outer: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (i + j > 2) {
      break outer
    }
  }
}

这类写法存在,但不宜滥用。多数情况下,提取函数或重构条件会更清晰。

forEach 不是语法级循环

数组的 forEach() 很常见,但它和 forfor...of 不完全是一类东西,它更像一个高阶方法。

js
;[1, 2, 3].forEach((item) => {
  console.log(item)
})

它适合简单遍历,但有几个限制:

  • 不能直接用 break
  • 不能直接用 continue
  • 处理异步串行流程时不如 for...of 直观

为什么 await 不适合直接放进 forEach

js
async function run() {
  const list = [1, 2, 3]

  list.forEach(async (item) => {
    await request(item)
    console.log(item)
  })

  console.log('end')
}

这里 forEach 不会等待每个异步回调完成,因此通常会先打印:

js
end

如果目标是串行执行,更适合写成:

js
async function run() {
  const list = [1, 2, 3]

  for (const item of list) {
    await request(item)
    console.log(item)
  }

  console.log('end')
}

串行与并发

串行

js
for (const item of list) {
  await request(item)
}

适合前后有依赖、需要按顺序处理的任务。

并发

js
await Promise.all(list.map((item) => request(item)))

适合互不依赖、希望一起执行的任务。

如何选择

for

适合:

  • 明确知道起点、终点和步进
  • 需要索引

while

适合:

  • 循环次数不固定
  • 更关注条件是否继续成立

for...of

适合:

  • 遍历数组、字符串、集合
  • 需要配合 await 做串行异步处理

for...in

适合:

  • 遍历对象属性名

使用建议

  • 遍历数组时,优先考虑 for...of 或数组方法。
  • 遍历对象属性时,优先考虑 for...inObject.keys()
  • 需要 breakcontinue 或串行 await 时,不要首选 forEach()
  • 复杂嵌套循环如果开始依赖标签跳转,通常说明代码可以进一步拆分。

基于 MIT 许可发布