浅谈ES6部分新特性之迭代器(Iterator)与for...of循环

151 阅读6分钟

今天哈士奇要给大家分享的是ES6的迭代器。在 ES6 中,迭代器(Iterator)与for...of循环是非常重要的概念,它为 JavaScript 中的各种数据结构提供了统一的访问机制以及循环遍历的方法。我们将深入探讨 ES6 迭代器的概念、工作原理以及如何在实际开发中使用迭代器和for...of循环。

什么是迭代器?

迭代器是一个对象,它具有一个 next() 方法,每次调用该方法都会返回一个包含 valuedone 属性的对象。其中,value 表示迭代器当前返回的值,done 表示迭代器是否已经完成迭代。当 donetrue 时,表示迭代器已经到达结尾,不再返回新的值。

迭代器的出现主要是为了帮助创造一个统一的接口,并且能够按照需要进行某些顺序的排序,同时也是为了服务for...of循环的出现。

迭代器的工作原理

ES6 中的迭代器工作原理非常简单,一个对象只要具有 Symbol.iterator 方法,并且该方法返回一个迭代器对象,那么该对象就是可迭代的。而迭代器对象则必须包含一个 next() 方法,用于返回迭代的下一个值。

让我们通过一个简单的例子来说明迭代器的工作原理:

const iterable = {
  [Symbol.iterator]() {
    let i = 0;
    return {
      next() {
        return {
          value: i++,
          done: i > 3
        };
      }
    };
  }
};

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

在这个例子中,我们定义了一个可迭代对象 iterable,它的 Symbol.iterator 方法返回了一个迭代器对象。迭代器对象通过 next() 方法返回一个递增的值,并在 i 大于 3 时设置 donetrue,表示迭代结束。

使用迭代器遍历数据结构

ES6 中的许多数据结构都实现了迭代器接口,比如数组、Set、Map 等。我们可以使用 for...of 循环来遍历这些数据结构,而无需关心它们的内部实现。

const array = [1, 2, 3];
const set = new Set([1, 2, 3]);
const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

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

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

for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}

自定义迭代器

除了使用内置的数据结构,我们还可以自定义迭代器来遍历自己的数据结构。下面是一个自定义迭代器的例子:

class Range {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }

  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) {
      yield i;
    }
  }
}

const range = new Range(1, 3);
for (const value of range) {
  console.log(value);
}

迭代器的使用场景

  1. 遍历数据结构: 迭代器最常见的用途是遍历各种数据结构,比如数组、集合、映射等。通过迭代器,我们可以便捷地访问数据结构中的每个元素,而无需了解数据结构的内部实现。

  2. 惰性求值: 迭代器可以实现惰性求值,即只有在需要时才会计算下一个值。这种特性在处理大量数据或者无限序列时非常有用,可以节省内存和计算资源。

  3. 逐步获取数据: 有些数据源并不是一次性就能获取所有数据的,比如网络请求或者文件读取。迭代器可以逐步获取数据,使得程序可以在数据到达时立即处理,而不需要等待所有数据都准备好。

  4. 实现自定义迭代逻辑: 我们可以通过实现自定义的迭代器来定义数据的迭代逻辑。这样可以更灵活地控制数据的遍历顺序和方式,满足特定的业务需求。

  5. 与生成器函数配合使用: 生成器函数可以简化迭代器的实现,使得代码更加清晰和易于理解。生成器函数可以用来生成迭代器对象,而不需要显式地编写next()方法。

总的来说,迭代器提供了一种统一的遍历方式,使得我们可以更加灵活和高效地处理各种数据结构。它是 JavaScript 中一个非常强大和重要的特性,值得我们深入学习和掌握。

可迭代的数据结构

那么问题来了,有哪些数据结构可以迭代呢?以下是一些常见的可迭代数据结构的示例:

  1. 数组(Array)
const array = [1, 2, 3];

const iterator = array[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
  1. 字符串(String)
const str = "hello";

const iterator = str[Symbol.iterator]();
console.log(iterator.next()); // { value: "h", done: false }
console.log(iterator.next()); // { value: "e", done: false }
console.log(iterator.next()); // { value: "l", done: false }
console.log(iterator.next()); // { value: "l", done: false }
console.log(iterator.next()); // { value: "o", done: false }
console.log(iterator.next()); // { value: undefined, done: true }
  1. 集合(Set)
const set = new Set([1, 2, 3]);

const iterator = set[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
  1. 映射(Map)
const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

const iterator = map[Symbol.iterator]();
console.log(iterator.next()); // { value: ['a', 1], done: false }
console.log(iterator.next()); // { value: ['b', 2], done: false }
console.log(iterator.next()); // { value: ['c', 3], done: false }
console.log(iterator.next()); // { value: undefined, done: true }

这些示例展示了如何通过调用对象的Symbol.iterator方法获取迭代器对象,并使用迭代器对象的next()方法逐个访问数据结构中的元素。这些数据结构都是 JavaScript 中常见的可迭代数据结构,它们实现了迭代器接口,因此可以直接用于for...of循环等迭代操作。

让我们再看看使用for...of循环是如何进行遍历的

当我们使用for...of循环时,实际上就是在使用迭代器来遍历数据结构。下面是使用for...of循环遍历上述数据结构的示例:

  1. 数组(Array)
const array = [1, 2, 3];

for (const value of array) {
  console.log(value);
}
  1. 字符串(String)
const str = "hello";

for (const char of str) {
  console.log(char);
}
  1. 集合(Set)
const set = new Set([1, 2, 3]);

for (const value of set) {
  console.log(value);
}
  1. 映射(Map)
const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

for (const entry of map) {
  console.log(entry);
}

在这些示例中,我们使用for...of循环遍历了数组、字符串、集合和映射中的元素。for...of循环会自动调用对象的迭代器来获取元素,并且在遍历完成后会自动停止。这使得代码更加简洁和易于理解,是遍历可迭代数据结构的常用方法之一。

总结

ES6 迭代器是一个非常强大的工具,它为 JavaScript 中的数据结构提供了统一的访问接口。通过使用迭代器与for...of循环,我们可以轻松地遍历各种数据结构,而无需关心它们的内部实现。希望哈士奇分享以后能帮助大家更好地理解和使用 ES6 迭代器!

假如您也和我一样,在准备春招。欢迎加我微信 shunwuyu ,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!