1. for…in
1. 原理
for...in
是一种用于 遍历对象属性 的循环
,它会枚举对象自身的和从原型链继承的 可枚举属性
。
- **可枚举属性:**指 enumerable 属性为 true 的键,这些属性可以通过 Object.keys() 或 for…in 枚举出来。
- **键名:**对于对象,键名始终是字符串;对于数组,键名是索引(以字符串形式返回)。
2. 使用场景
for...in 主要用于遍历对象的属性
,而不适用于遍历数组
。尽管可以用它遍历数组
,但由于数组的索引会被转为字符串形式
,且可能遍历到原型链中的属性
,因此会产生潜在问题。
- 适合遍历对象
const person = { name: "Alice", age: 25, job: "Engineer" };
for (let key in person) {
console.log(key); // name, age, job
console.log(person[key]); // Alice, 25, Engineer
}
- 不推荐用于数组
const arr = [1, 2, 3];
for (let index in arr) {
console.log(index); // 输出:'0', '1', '2'(索引作为字符串)
console.log(arr[index]); // 输出:1, 2, 3
}
- 为什么不推荐?
-
索引是字符串,而非数字。
-
如果数组有自定义属性,for…in 会将这些属性也枚举出来:
const arr = [1, 2, 3]; arr.custom = "hello"; for (let key in arr) { console.log(key); // '0', '1', '2', 'custom' }
- for…in 的原型链问题
for…in 会遍历对象的 原型链,这可能带来意外结果:
const obj = { a: 1 };
Object.prototype.b = 2;
for (let key in obj) {
console.log(key); // 输出:'a', 'b'
}
解决方法:使用 Object.hasOwnProperty() 检查是否为对象自身属性
:
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key); // 只输出:'a'
}
}
- 高级用法
配合 Object.keys()、Object.values()、Object.entries()
- Object.keys(obj):获取对象的所有 自身属性的键。
- Object.values(obj):获取对象的所有 自身属性的值。
- Object.entries(obj):获取对象的所有键值对,返回数组形式。
const obj = { a: 1, b: 2, c: 3 };
Object.keys(obj).forEach((key) => {
console.log(key, obj[key]); // a 1, b 2, c 3
});
2. for…of
- 原理
for…of 是 ES6 引入的一种语法,用于遍历 可迭代对象(iterable)
。一个对象是可迭代的,必须实现了 Symbol.iterator
接口。
- 可迭代对象:
包括数组、字符串、Map、Set、生成器
等。 - 返回值:直接返回每次迭代的值,而不是键名。
- 使用场景
for…of 适用于遍历 数组、字符串、Map、Set 等所有实现了迭代协议的对象。
-
遍历数组
const arr = [1, 2, 3]; for (let value of arr) { console.log(value); // 1, 2, 3 }
-
遍历字符串
const str = "hello"; for (let char of str) { console.log(char); // h, e, l, l, o }
-
遍历 Map
const map = new Map([ ["a", 1], ["b", 2], ]); for (let [key, value] of map) { console.log(key, value); // a 1, b 2 }
-
遍历 Set
const set = new Set([1, 2, 3]); for (let value of set) { console.log(value); // 1, 2, 3 }
- 高级用法
-
与生成器函数配合
生成器函数返回一个可迭代对象,可以直接用 for…of 遍历:function* generator() { yield 1; yield 2; yield 3; } for (let value of generator()) { console.log(value); // 1, 2, 3 }
-
与数组解构配合
结合解构,可以简洁地获取数组元素:const arr = [[1, 2], [3, 4], [5, 6]]; for (let [a, b] of arr) { console.log(a, b); // 1 2, 3 4, 5 6 }
- 注意事项
-
for…of 无法直接遍历对象:
const obj = { a: 1, b: 2 }; // 报错:TypeError: obj is not iterable for (let value of obj) { console.log(value); }
解决方法:使用
Object.entries()
将对象转换为可迭代的数组:for (let [key, value] of Object.entries(obj)) { console.log(key, value); // a 1, b 2 }
-
区分 for…of 和 for…in 的适用场景:
- for…in 遍历对象的键名。
- for…of 遍历可迭代对象的值。