在 JavaScript 中,for...in
和 for...of
是两种常用的循环结构,但它们有着不同的用途和行为。很多初学者容易混淆这两者,本文将详细解析它们的区别、适用场景以及注意事项。
目录
-
for…in 循环
- 基本用法
- 遍历对象属性
- 注意事项
-
for…of 循环
- 基本用法
- 可迭代对象
- 与数组的结合使用
-
主要区别对比
-
何时使用哪种循环
-
实际应用示例
-
总结
for…in 循环
基本用法
for...in
语句用于遍历对象的可枚举属性(包括原型链上的可枚举属性)。
for (variable in object) {
// 执行的代码
}
遍历对象属性
const person = {
name: 'Alice',
age: 25,
occupation: 'Developer'
};
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}
// 输出:
// name: Alice
// age: 25
// occupation: Developer
注意事项
-
遍历顺序不保证:
for...in
不保证属性的遍历顺序,特别是在不同 JavaScript 引擎中可能有差异。 -
会遍历原型链上的属性:
function Person() { this.name = 'Bob'; } Person.prototype.age = 30; const bob = new Person(); for (const prop in bob) { console.log(prop); // 输出 name 和 age }
可以使用
hasOwnProperty()
来过滤:for (const prop in bob) { if (bob.hasOwnProperty(prop)) { console.log(prop); // 只输出 name } }
-
不推荐用于数组:
const arr = ['a', 'b', 'c']; for (const index in arr) { console.log(index); // 输出 "0", "1", "2" }
虽然可以工作,但有潜在问题(如可能遍历到非数字属性)。
for…of 循环
基本用法
for...of
语句在可迭代对象(包括 Array, Map, Set, String, TypedArray, arguments 对象等)上创建一个迭代循环。
for (variable of iterable) {
// 执行的代码
}
可迭代对象
for...of
只能用于实现了 [Symbol.iterator]
方法的对象:
const arr = ['a', 'b', 'c'];
for (const value of arr) {
console.log(value); // 输出 "a", "b", "c"
}
const str = 'hello';
for (const char of str) {
console.log(char); // 输出 "h", "e", "l", "l", "o"
}
const set = new Set([1, 2, 3]);
for (const num of set) {
console.log(num); // 输出 1, 2, 3
}
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
console.log(`${key}: ${value}`); // 输出 "a: 1", "b: 2"
}
与数组的结合使用
for...of
是遍历数组元素的理想选择:
const fruits = ['apple', 'banana', 'orange'];
for (const fruit of fruits) {
console.log(fruit);
}
// 输出:
// apple
// banana
// orange
主要区别对比
特性 | for…in | for…of |
---|---|---|
用途 | 遍历对象属性 | 遍历可迭代对象的值 |
返回值 | 属性名(key) | 属性值(value) |
可遍历对象 | 任意对象 | 可迭代对象(Array, Map等) |
遍历原型链属性 | 是 | 否 |
数组遍历 | 遍历索引(字符串) | 遍历元素值 |
性能 | 相对较慢 | 相对较快 |
引入版本 | ES1 | ES6 |
何时使用哪种循环
-
使用
for...in
当:- 需要遍历对象的所有可枚举属性
- 需要检查对象是否具有某些属性
- 需要遍历原型链上的属性(或明确使用 hasOwnProperty 过滤)
-
使用
for...of
当:- 需要遍历数组的元素值
- 需要遍历其他可迭代对象(Map, Set等)的值
- 需要更简洁的语法且不关心索引/键
-
都不使用时:
- 对于简单的数组遍历,传统的
for
循环有时性能更好 - 需要中断循环时,
forEach
无法使用break
,此时for...of
更合适
- 对于简单的数组遍历,传统的
实际应用示例
示例1:对象属性操作
const user = {
id: 1,
name: 'John Doe',
email: 'john@example.com',
isAdmin: false
};
// 使用 for...in 将所有布尔属性转换为字符串
for (const key in user) {
if (typeof user[key] === 'boolean') {
user[key] = user[key].toString();
}
}
console.log(user); // isAdmin 现在是 "false"
示例2:数组元素处理
const scores = [85, 92, 78, 95, 88];
let total = 0;
// 使用 for...of 计算总分
for (const score of scores) {
total += score;
}
console.log(`平均分: ${total / scores.length}`); // 平均分: 87.6
示例3:结合解构赋值
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];
// 使用 for...of 和解构
for (const { id, name } of users) {
console.log(`用户ID: ${id}, 姓名: ${name}`);
}
总结
for...in
用于遍历对象的可枚举属性,包括原型链上的属性for...of
用于遍历可迭代对象的值,如数组元素、Map/Set 的项等- 对于数组遍历,优先使用
for...of
而不是for...in
- 两种循环各有适用场景,理解它们的差异有助于写出更清晰、更高效的代码
掌握 for...in
和 for...of
的区别和正确用法,将使你在 JavaScript 开发中能够更灵活地处理各种数据结构和对象遍历需求。