在 JavaScript 中,for...in
和 for...of
都是用于遍历数据结构的循环语句,但它们的应用场景和行为有显著差异。理解两者的区别对于编写高效、可维护的代码至关重要。
✅ 一句话总结
for...in
用于遍历对象的可枚举属性名(键) ,适合处理普通对象;而for...of
用于遍历实现了Symbol.iterator
接口的可迭代对象的值,适用于数组、字符串、Map、Set 等。
✅ 一、for...in
循环
🔹 语法
javascript
for (variable in object) {
// 执行语句
}
🔹 特点
- 遍历对象的所有可枚举属性(包括原型链上的);
- 返回的是属性名(字符串),不是值;
- 主要用于普通对象(Plain Object) 的遍历;
🔹 示例
javascript
const obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
console.log(key); // 输出: a, b, c
console.log(obj[key]); // 输出: 1, 2, 3
}
🔹 注意事项
- 会遍历原型链上的可枚举属性:
javascript
Object.prototype.extra = 'extra';
for (let key in obj) {
console.log(key); // a, b, c, extra
}
✅ 建议使用
hasOwnProperty()
过滤:
javascript
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key, obj[key]);
}
}
- 不推荐用于数组索引遍历 :
- 虽然可以遍历数组,但顺序可能不稳定;
- 可能会遍历到手动添加的非数字属性;
javascript
const arr = [10, 20, 30];
arr.name = 'numbers';
for (let i in arr) {
console.log(i); // 0, 1, 2, name(包括非索引属性)
}
✅ 二、for...of
循环
🔹 语法
javascript
for (variable of iterable) {
// 执行语句
}
🔹 特点
- 遍历实现了
[Symbol.iterator]()
方法的可迭代对象; - 返回的是元素的值,不是键;
- 适用于:
Array
、String
、Map
、Set
、arguments
、NodeList 等;
🔹 示例
javascript
const arr = [10, 20, 30];
for (let value of arr) {
console.log(value); // 输出: 10, 20, 30
}
const str = "hello";
for (let char of str) {
console.log(char); // h, e, l, l, o
}
const map = new Map([['a', 1], ['b', 2]]);
for (let [key, value] of map) {
console.log(key, value); // a 1, b 2
}
🔹 自定义对象也可使用 for...of
只要对象实现了 Symbol.iterator
接口:
javascript
const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (let value of myIterable) {
console.log(value); // 1, 2, 3
}
✅ 三、核心区别对比表
特性 | for...in |
for...of |
---|---|---|
遍历目标 | 对象的可枚举属性名(键) | 可迭代对象的值 |
适用类型 | 普通对象(Object) | 数组、字符串、Map、Set、arguments、NodeList 等 |
是否遍历原型链 | 是 | 否 |
返回内容 | 属性名(字符串) | 元素值 |
是否支持 break/continue | 是 | 是 |
是否依赖 Symbol.iterator |
否 | 是 |
✅ 四、常见误用与最佳实践
❌ 错误用法:用 for...in
遍历数组值
javascript
// ❌ 不推荐
for (let i in arr) {
console.log(arr[i]);
}
✅ 推荐使用:
javascript
// ✅ 推荐
for (let value of arr) {
console.log(value);
}
// 或使用数组方法
arr.forEach(value => console.log(value));
✅ 正确使用场景总结
数据类型 | 推荐循环方式 |
---|---|
普通对象 {} |
for...in + hasOwnProperty |
数组 [] |
for...of 、forEach 、map 等 |
字符串 | for...of |
Map / Set | for...of |
arguments / NodeList | for...of |
✅ 五、一句话总结
用
for...in
遍历对象的键 ,用for...of
遍历可迭代对象的值。选择正确的工具,让代码更清晰、更安全。
💡 拓展知识
🔹 如何判断一个对象是否可迭代?
javascript
function isIterable(obj) {
return obj != null && typeof obj[Symbol.iterator] === 'function';
}
isIterable([1, 2, 3]); // true
isIterable('hello'); // true
isIterable({}); // false
🔹 for...of
背后的机制
for...of
本质上是调用对象的 Symbol.iterator
方法,获取一个迭代器(Iterator),然后不断调用 .next()
方法直到 done: true
。