JavaScript 中的 for...of 和 for...in 的区别你知道吗?

168 阅读3分钟

前言

在 JavaScript 中,for...offor...in 循环都是用来遍历数据结构的循环语句,但它们之间有着显著的区别。

for...of 循环

for...of 循环是 ES6 中引入的一种遍历可迭代对象的循环语句。它可以迭代数组、字符串、Set、Map、生成器等可迭代对象,以及任何实现了迭代器协议的对象。for...of 循环提供了一种简洁、直观的遍历方式,语法如下:

for (const item of items) {
    // 执行操作
}

其中,items 是一个可迭代对象,item 则是迭代过程中的每个元素值。

迭代器协议

迭代器协议(Iterator Protocol)是一种在 JavaScript 中用于定义可迭代对象的协议,它使得对象能够自定义迭代行为。 迭代器协议定义了一种标准的方式来让对象实现迭代器接口,使得这些对象可以被 for...of 循环、Array.from() 方法等接受可迭代对象的函数所使用。

迭代器协议要求对象必须具有一个名为 Symbol.iterator 的方法,该方法返回一个遵循迭代器协议的迭代器对象。 迭代器对象本身需要实现 next() 方法,该方法用于返回迭代过程中的下一个值,并且在迭代结束时返回一个包含 valuedone 属性的对象。其中,value 是迭代器返回的当前值,而 done 是一个布尔值,表示迭代是否结束。

下面的示例,演示了如何使用迭代器协议来定义一个可迭代对象和一个迭代器对象:

const iterableObject = {
    values: ['a', 'b', 'c'],
    [Symbol.iterator]: function() {
        let index = 0;
        return {
            next: () => {
                if (index < this.values.length) {
                    return { value: this.values[index++], done: false };
                } else {
                    return { value: undefined, done: true };
                }
            }
        };
    }
};

// 使用 for...of 循环遍历可迭代对象
for (const value of iterableObject) {
    console.log(value); // 输出:a b c
}

在上面的示例中,iterableObject是一个包含values属性的对象。通过实现Symbol.iterator方法,我们为iterableObject定义了一个迭代器,该迭代器能够在每次调用next()方法时返回values中的下一个值,并在迭代结束时返回 done: true

for...in 循环

**for...in 循环用于遍历对象的可枚举属性,它并不是专门用来遍历数组或类似数据结构的。**该循环语句会遍历对象的所有可枚举属性,包括自身属性和原型链上的属性。语法如下:

for (const key in object) {
    if (object.hasOwnProperty(key)) {
        // 执行操作
    }
}

其中,object 是一个对象,key 是对象的属性名。

区别

  • 遍历对象 vs. 遍历元素

    • for...in 遍历的是对象的属性名,而 for...of 遍历的是可迭代对象的元素值。
  • 遍历顺序

    • for...in 循环遍历对象的属性时,不保证属性的顺序,可能会遍历出任意顺序的属性。
    • for...of 循环遍历可迭代对象时,会按照元素在迭代器中的顺序进行遍历。
  • 使用场景

    • for...in 循环适用于遍历普通对象的属性,不推荐用于遍历数组,因为它可能会遍历到原型链上的属性,而且不保证遍历顺序。
    • for...of 循环适用于遍历数组、字符串等可迭代对象,是一种更加直观和安全的遍历方式。

总结

for...offor...in 循环在 JavaScript 中都有着重要的作用,但它们用于不同的场景。for...of 更适用于遍历数组、字符串等可迭代对象,而 for...in 更适用于遍历对象的属性。