1. 基本 for 循环
for (let i = 0; i < 10; i++) {console.log(i);
}
特点:
- 适用于已知循环次数的情况
- 使用数字索引进行迭代
- 可以精确控制循环过程
- 性能最好,开销最小
2. for…in 循环
// 数组示例
for (let i in [1, 2, 3]) {console.log(i, typeof i); // 输出 "0 string", "1 string", "2 string"
}// 对象示例
for (let i in { a: 1, b: 2 }) {console.log(i, typeof i); // 输出 "a string", "b string"
}
特点:
- 遍历对象的可枚举属性键(包括继承的属性)
- 返回的是属性键(字符串类型)
- 对于数组,遍历的是索引
- 对于对象,遍历的是属性名
- 会遍历原型链上的可枚举属性
3. for…of 循环(补充)
// 数组示例
for (let value of [1, 2, 3]) {console.log(value); // 输出 1, 2, 3
}// 对象不能直接使用 for...of(除非是可迭代对象)
for (let [key, value] of Object.entries({ a: 1, b: 2 })) {console.log(key, value); // 输出 "a 1", "b 2"
}
详细对比
数组遍历对比
const arr = ["a", "b", "c"];
arr.customProperty = "custom";// 基本 for 循环
for (let i = 0; i < arr.length; i++) {console.log(i, arr[i]); // 0 'a', 1 'b', 2 'c'
}// for...in 循环
for (let i in arr) {console.log(i, arr[i]); // "0" "a", "1" "b", "2" "c", "customProperty" "custom"
}// for...of 循环
for (let value of arr) {console.log(value); // "a", "b", "c"
}
对象遍历对比
const obj = { a: 1, b: 2, c: 3 };// 基本 for 循环不能直接用于对象// for...in 循环
for (let key in obj) {console.log(key, obj[key]); // "a" 1, "b" 2, "c" 3
}// for...of 需要配合 Object.keys/values/entries
for (let key of Object.keys(obj)) {console.log(key, obj[key]); // "a" 1, "b" 2, "c" 3
}
性能对比
const largeArray = new Array(1000000).fill(0).map((_, i) => i);// 基本 for 循环 - 最快
console.time("for loop");
for (let i = 0; i < largeArray.length; i++) {// 处理 largeArray[i]
}
console.timeEnd("for loop");// for...in 循环 - 较慢
console.time("for...in loop");
for (let i in largeArray) {// 处理 largeArray[i]
}
console.timeEnd("for...in loop");// for...of 循环 - 中等
console.time("for...of loop");
for (let value of largeArray) {// 处理 value
}
console.timeEnd("for...of loop");
使用场景建议
何时使用基本 for 循环
// 1. 需要索引值
for (let i = 0; i < array.length; i++) {console.log(`Index: ${i}, Value: ${array[i]}`);
}// 2. 需要反向遍历
for (let i = array.length - 1; i >= 0; i--) {console.log(array[i]);
}// 3. 需要跳过某些元素
for (let i = 0; i < array.length; i += 2) {console.log(array[i]);
}
何时使用 for…in
// 1. 遍历对象属性
const config = { theme: "dark", lang: "en", version: "1.0" };
for (let key in config) {if (config.hasOwnProperty(key)) {// 避免遍历原型属性console.log(`${key}: ${config[key]}`);}
}// 2. 需要属性名而非值
for (let index in array) {console.log(`Array index: ${index}`);
}
何时使用 for…of
// 1. 只关心值而不关心索引
for (let value of array) {console.log(value);
}// 2. 遍历其他可迭代对象
for (let char of "hello") {console.log(char); // "h", "e", "l", "l", "o"
}// 3. 遍历 Map 和 Set
const map = new Map([["a", 1],["b", 2],
]);
for (let [key, value] of map) {console.log(key, value);
}
注意事项
for…in 的陷阱
Array.prototype.extraMethod = function () {};const arr = [1, 2, 3];// for...in 会遍历到原型方法
for (let i in arr) {console.log(i, arr[i]); // 会输出 "extraMethod" function
}// 解决方案:使用 hasOwnProperty 检查
for (let i in arr) {if (arr.hasOwnProperty(i)) {console.log(i, arr[i]); // 只输出数组索引}
}