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]); // 只輸出數組索引}
}