实现可迭代对象

通过 Symbol.iterator 让对象支持 for...of 循环

问题

如何把一个普通对象变成可迭代对象,使其支持 for...of 循环?

解答

什么是可迭代对象

可迭代对象是指实现了迭代器协议的对象,可以在 for...of 循环中使用。数组、字符串、Map、Set 等都是可迭代对象。

迭代器协议

迭代器是一个对象,必须实现 next() 方法,该方法返回包含两个属性的对象:

  • value:序列中的下一个值
  • done:布尔值,表示是否已迭代完成

实现可迭代对象

要让对象可迭代,需要为其添加 [Symbol.iterator] 方法,该方法返回一个迭代器对象。

let info = {
  bears: ['ice', 'panda', 'grizzly'],
  [Symbol.iterator]: function() {
    let index = 0;
    let bears = this.bears;
    
    return {
      next: function() {
        if (index < bears.length) {
          return { value: bears[index++], done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};

// 使用 for...of 遍历
for (let bear of info) {
  console.log(bear); // 'ice', 'panda', 'grizzly'
}

实现范围迭代器

创建一个生成指定范围整数的迭代器:

function makeRangeIterator(start = 0, end = Infinity, step = 1) {
  let nextIndex = start;
  let iterationCount = 0;
  
  const rangeIterator = {
    next: function() {
      if (nextIndex < end) {
        let result = { value: nextIndex, done: false };
        nextIndex += step;
        iterationCount++;
        return result;
      }
      return { value: iterationCount, done: true };
    }
  };
  
  return rangeIterator;
}

const iterator = makeRangeIterator(1, 10, 2);
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 3
console.log(iterator.next().value); // 5

关键点

  • 可迭代对象必须实现 [Symbol.iterator] 方法
  • [Symbol.iterator] 方法需要返回一个包含 next() 方法的迭代器对象
  • next() 方法返回 { value, done } 格式的对象
  • 迭代器只能消耗一次,迭代完成后 done 应始终为 true
  • 迭代器可以表示无限序列,不必像数组那样预先分配所有元素