JavaScript 常用循环语句对比:for、for...in、for...of 与 forEach

作者:青柠时间:2026-10-25 01:11:30浏览:195

本文详细对比JavaScript中四种常用循环语句:普通for、for...in、for...of和forEach。分析它们在Array、Object、Set和Map四种数据结构中的支持情况,重点讲解原型属性过滤、迭代器行为以及break/continue/return语句的使用限制,帮助开发者根据场景选择最合适的循环方式。

JavaScript提供了多种循环语句,包括普通for、for...in、for...of以及forEach。本文旨在对比这四种循环方式在Array、Object、Set(ES6新增)和Map(ES6新增)这四种数据结构中的支持情况及具体区别。

首先,我们需要构建用于测试的四种数据类型的数据样本。


let arr = [1, 2, 3, 4, 5, 6];
let obj = { a: 1, b: 2, c: 3 };
let map = new Map([['a', 'a1'], ['b', 'b2'], ['c', 'c3']]);
let set = new Set(['a', 'b', 'c']);

1 普通 for 循环

普通 for 循环在 Array 类型数据中可以直接使用。在遍历数组时,该循环机制实际上是在遍历数组的下标(索引),开发者需要通过获取到的下标来访问并取值。


for (let i = 0; i < arr.length; i++) { // i是下标(索引)
  console.log(i)
  console.log(arr[i])
}

2 for...in 循环

for...in 语句既可用于 Array,也可用于 Object。需要特别注意的是,该循环会遍历对象原型链上的属性,这意味着原型上定义的属性也会被枚举出来。

Array 场景


let arr = [1, 2, 3, 4, 5, 6];
Array.prototype.a = "1"

for (let i in arr) {  // i是下标(索引)
  console.log(i)
  console.log(arr[i])
}

从运行结果可以看出,原型上定义的属性也被循环出来了,这通常并非开发者所期望的结果。我们可以通过 hasOwnProperty 方法来过滤掉继承自原型的属性,从而只获取对象自身的属性。


let arr = [1, 2, 3, 4, 5, 6];
Array.prototype.a = "1"

for (let i in arr) {  // i是下标(索引)
  if (arr.hasOwnProperty(i)) {
    console.log(i)
    console.log(arr[i])
  }
}

Object 场景


let obj = { a: 1, b: '2', c: 3 };
Object.prototype.d = 4

for (let key in obj) {  // key是键
  console.log(key)
  console.log(obj[key])
}

对于 Object 类型,同样存在原型属性被循环出来的问题。解决方法与 Array 一致,利用 hasOwnProperty 进行过滤即可排除原型属性。


for (let key in obj) {  // key是键
  if (obj.hasOwnProperty(key)) {
    console.log(key)
    console.log(obj[key])
  }
}

3 for...of 循环

for...of 循环的支持范围更广,在 Array、Object、Set 和 Map 中均可使用。

Array 场景

虽然 Array 本质上也是对象,我们可以在其隐式原型(__proto__)中找到定义好的方法,但 for...of 提供了更直接的迭代方式。


for (let key of arr.keys()) {  // key是下标
  console.log(key)
}
for (let value of arr) {     // value是值
  console.log(value)
}
for (let value of arr.values()) { // value是值
  console.log(value)
}
for (let [key, value] of arr.entries()) { // key是下标 value是值
  console.log(key,value)
}

Object 场景


for (let [key, value] of Object.entries(obj)) { // key是下标 value是值
  console.log(key, value)
}

Set 场景

由于 Set 数据结构本身不包含重复值,其 keys() 和 values() 方法返回的结果是一致的。因此,下面列出的四种遍历方式输出的结果是相同的。


for (let key of set.keys()) {  
  console.log(key)
}
for (let value of set) {     
  console.log(value)
}
for (let value of set.values()) { 
  console.log(value)
}
for (let [key, value] of set.entries()) { 
  console.log(key, value)
}

Map 场景


for (let key of map.keys()) { 
  console.log(key)
}
for (let value of map) {     
  console.log(value)
}
for (let value of map.values()) { 
  console.log(value)
}
for (let [key, value] of map.entries()) { 
  console.log(key, value)
}

在 for...of 循环中,可以使用 break 和 continue 语句来跳出或跳过当前迭代,也可以使用 return 语句从包含该循环的函数体中直接返回。


for (let key of arr.keys()) {  // key是下标
  if (key == 3) {
    return
  }
  console.log(key)
}
for (let key of arr.keys()) {  // key是下标
  if (key == 3) {
    break
  }
  console.log(key)
}
for (let key of arr.keys()) {  // key是下标
  if (key == 3) {
    continue
  }
  console.log(key)
}

4 forEach 方法

forEach 方法在 Array、Set 和 Map 中均可使用。但与 for...of 不同,forEach 的回调函数内部不能使用 break 或 continue 语句来跳出循环,也不能通过 return 语句从外层函数返回。

Array 场景


arr.forEach((value, index) => {
  console.log(value, index)
})

Set 场景


set.forEach((value, key) => {
  console.log(value, key)
})

Map 场景


map.forEach((value, key) => {
  console.log(value, key)
})

break、continue 和 return 的行为差异

在 forEach 中使用 continue 会触发语法错误提示。


Illegal continue statement: no surrounding iteration statement

在 forEach 中使用 break 同样会触发语法错误提示。


Illegal break statement

在 forEach 中使用 return,并不会像普通函数那样返回,而是仅仅结束当前这一次回调的执行,循环会继续执行后续元素。

5 总结

普通 for 循环适用于 Array,通过下标索引取值;for...in 适用于 Array 和 Object,但需注意过滤原型属性;for...of 支持 Array、Object、Set 和 Map,且支持 break、continue 和 return;forEach 适用于 Array、Set 和 Map,但不支持 break、continue 或 return 跳出循环。

至此,关于 JavaScript 常用 for 循环的详细对比介绍完毕。如需了解更多 JS for 循环相关内容,建议搜索本站过往文章或继续阅读后续系列文章,感谢大家的支持。

作者最新文章