ZetCode

JavaScript [Symbol.iterator] 方法

最后修改于 2025 年 4 月 4 日

在本文中,我们将展示如何使用 JavaScript 中的 [Symbol.iterator] 方法创建可迭代对象。

可迭代对象和迭代器

可迭代对象是实现 [Symbol.iterator] 方法的对象。此方法返回一个迭代器对象。迭代器必须实现一个 next 方法,该方法返回一个具有 valuedone 属性的对象。

可迭代对象可以与 for...of 循环和扩展运算符一起使用。内置类型,如 Array、String、Map 和 Set 默认是可迭代的。[Symbol.iterator] 方法允许自定义对象变得可迭代。

迭代器协议定义了一种产生一系列值的标准方法。当一个对象实现了这个协议时,它可以被期望迭代对象的 JavaScript 语言结构所使用。这提供了对象遍历方式的灵活性。

基本 [Symbol.iterator] 示例

以下示例演示了 [Symbol.iterator] 方法的基本用法。

main.js
const myIterable = {
  [Symbol.iterator]: function() {
    let step = 0;
    return {
      next: function() {
        step++;
        if (step <= 3) {
          return { value: step, done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};

for (const value of myIterable) {
  console.log(value);
}

我们创建一个简单的可迭代对象,它生成值 1、2 和 3。[Symbol.iterator] 方法返回一个带有 next 方法的迭代器对象。for...of 循环使用该可迭代对象。

$ node main.js
1
2
3

自定义范围迭代器

此示例展示了如何创建自定义范围迭代器。

main.js
function makeRange(start, end, step = 1) {
  let current = start;
  return {
    [Symbol.iterator]: function() {
      return {
        next: function() {
          if (current <= end) {
            const value = current;
            current += step;
            return { value, done: false };
          }
          return { done: true };
        }
      };
    }
  };
}

for (const num of makeRange(1, 10, 2)) {
  console.log(num);
}

我们创建一个范围迭代器,它以给定的步长生成从开始到结束的数字。迭代器将其状态保存在 current 变量中。这演示了如何创建参数化迭代器。

$ node main.js
1
3
5
7
9

迭代对象属性

此示例展示了如何使对象的属性可迭代。

main.js
const person = {
  name: 'John',
  age: 30,
  city: 'New York',
  [Symbol.iterator]: function() {
    const keys = Object.keys(this);
    let index = 0;
    return {
      next: () => {
        if (index < keys.length) {
          const key = keys[index++];
          return { value: `${key}: ${this[key]}`, done: false };
        }
        return { done: true };
      }
    };
  }
};

for (const prop of person) {
  console.log(prop);
}

我们通过实现 [Symbol.iterator] 使一个普通对象可迭代。迭代器将键值对作为字符串生成。当你想要控制对象的属性如何被枚举时,这种模式很有用。

$ node main.js
name: John
age: 30
city: New York

无限迭代器

此示例演示了一个永远不会完成的无限迭代器。

main.js
const infiniteSequence = {
  [Symbol.iterator]: function() {
    let n = 0;
    return {
      next: function() {
        n++;
        return { value: n, done: false };
      }
    };
  }
};

const iterator = infiniteSequence[Symbol.iterator]();
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);

我们创建一个迭代器,它生成一个无限的数字序列。由于它从不返回 done: true,如果与 for...of 一起使用,它会导致一个无限循环。相反,我们手动调用 next 来获取值。

$ node main.js
1
2
3

与生成器结合

此示例展示了如何将生成器与 [Symbol.iterator] 一起使用。

main.js
const fibonacci = {
  *[Symbol.iterator]() {
    let a = 0, b = 1;
    while (true) {
      yield a;
      [a, b] = [b, a + b];
    }
  }
};

let count = 0;
for (const num of fibonacci) {
  console.log(num);
  if (count++ >= 9) break;
}

我们使用生成器函数作为 [Symbol.iterator] 方法来实现斐波那契数列。生成器通过自动处理状态和迭代器协议来简化迭代器实现。yield 关键字生成值。

$ node main.js
0
1
1
2
3
5
8
13
21
34

来源

迭代协议 - 语言参考

在本文中,我们演示了如何使用 [Symbol.iterator] 方法在 JavaScript 中创建自定义可迭代对象。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 JS 数组函数。