【介绍】
for-in
和 for-of
都是 JavaScript 中用于遍历数据结构的循环语句,但它们的工作原理和适用场景有所不同。特别是它们在遍历对象时的行为是不同的。
【区别】
for-in
遍历对象
for-in
是用于遍历对象的 可枚举属性的键名(属性名),它会遍历对象自身以及继承的属性(从原型链继承的属性)。这种遍历顺序并不是固定的,因此在遍历时,键名的顺序不一定是按添加顺序排列的。
示例:
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
}
for-in
遍历的是 属性名(键),可以通过obj[key]
获取对应的值。- 它也会遍历继承自原型链的属性。
注意:
for-in
可能遍历到对象的原型链上的属性,因此通常在遍历对象时要使用hasOwnProperty
来过滤掉继承的属性:
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key, obj[key]); // 只输出 obj 自有属性
}
}
for-of
遍历对象
for-of
主要用于遍历 可迭代对象(如数组、字符串、Map、Set 等),它可以直接遍历这些对象的 元素值。普通对象(如{}
)不是可迭代对象,因此不能使用for-of
遍历对象。
示例:
const arr = [1, 2, 3, 4];
for (let value of arr) {
console.log(value); // 输出:1, 2, 3, 4
}
for-of
遍历的是 数组元素的值,并不像for-in
那样遍历键名。
区别总结:
特性 | for-in | for-of |
---|---|---|
遍历目标 | 对象的 属性名(键名) | 可迭代对象的 值 |
适用场景 | 用于遍历对象的属性 | 用于遍历数组、字符串、Set、Map 等可迭代对象的值 |
遍历顺序 | 遍历对象属性的顺序不固定 | 遍历顺序是固定的,按数组的顺序遍历元素 |
遍历对象时的行为 | 遍历对象的所有可枚举属性,包括原型链上的属性 | 不适用于对象,适用于数组等可迭代对象 |
是否遍历原型链 | 会遍历继承的属性 | 不会遍历原型链上的元素 |
对象如何使用 for-of
遍历?
由于普通对象是不可迭代的,不能直接使用 for-of
来遍历对象。如果你希望遍历对象的值或键,可以先使用 Object.keys()
, Object.values()
或 Object.entries()
来将对象转化为可迭代的结构,然后使用 for-of
遍历。
示例:使用 for-of
遍历对象的键和值
const obj = { a: 1, b: 2, c: 3 };
// 遍历键
for (let key of Object.keys(obj)) {
console.log(key); // 输出:a, b, c
}
// 遍历值
for (let value of Object.values(obj)) {
console.log(value); // 输出:1, 2, 3
}
// 遍历键值对
for (let [key, value] of Object.entries(obj)) {
console.log(key, value); // 输出:a 1, b 2, c 3
}
【总结】
for-in
用于遍历 对象的属性名,适合遍历对象本身及其原型链上的属性。for-of
用于遍历 可迭代对象的元素值,常用于遍历数组、字符串、Set 和 Map 等类型。对于普通对象,通常先将对象转化为可迭代的结构后才能使用for-of
。
补充
for-in
遍历对象时属性顺序不固定
在 JavaScript 中,for-in
遍历对象时的属性顺序确实不是固定的。特别是对于对象的 数字类型的键名,浏览器的行为可能会不同,但根据 ECMAScript 规范,对于普通对象来说, 字符串类型的键名会按添加顺序遍历,而数字键名会按数值顺序遍历。
然而,这个顺序并不是严格保证的,尤其是在老版本的浏览器中,可能会出现不同的行为。为了演示这种不固定顺序的行为,我们可以考虑以下代码示例,展示不同类型的键名如何影响 for-in
的遍历顺序。
示例:for-in
遍历顺序
const obj = {
'3': 'three', // 数字类型的键
'1': 'one', // 数字类型的键
'2': 'two', // 数字类型的键
'a': 'apple', // 字符串类型的键
'b': 'banana', // 字符串类型的键
'z': 'zebra' // 字符串类型的键
};
for (let key in obj) {
console.log(key); // 输出属性名(键)
}
输出:
1
2
3
a
b
z
解释:
- 数字键(
'1'
,'2'
,'3'
)按数值顺序排列,先输出数字键。 - 字符串键(
'a'
,'b'
,'z'
)按添加顺序排列,紧随其后。
示例:for-in
的原型链行为
for-in
不仅会遍历对象本身的属性,还会遍历继承的属性(即原型链上的属性)。因此,如果对象有继承的属性或方法,for-in
会遍历这些继承的属性。
const obj = {
name: 'Alice',
age: 25
};
Object.prototype.sayHello = function() {
console.log('Hello!');
};
for (let key in obj) {
console.log(key); // 输出:name, age, sayHello
}
输出:
name
age
sayHello
解释:
for-in
会遍历 obj
的自有属性和继承的属性,因此 sayHello
也被遍历到。
小结:
for-in
的遍历顺序并不完全固定,尤其是数字类型的键名的顺序可能因不同的 JavaScript 引擎而有所不同。- 对于字符串类型的键,
for-in
通常会按照对象中添加的顺序遍历。 for-in
还会遍历继承自原型链上的属性,因此需要特别注意过滤掉继承的属性。