What makes JavaScript Iterables Iterable? - Iterator Protocol and Generator
什么让 JavaScript 数据结构能够被迭代? 了解 Iterator Protocol 与 Generator
前言
你有想过为什么数组可以被迭代处理(for...of)但对象不行吗?JavaScript Iterables (可迭代对象)背后依赖 Iterator Protocol 来实现可被迭代的数据结构。
只要一个数据结构实现了这个协议,就能成为 Iterable,被 for...of、展开运算符、Array.from() 或解构赋值等……语法直接操作。
基于 Iterator Protocol 的概念更是扩展到 Generator Function 相关的知识点,可以创造更多特殊的数据结构。
Iterables
所谓「可迭代」,指的是对象实现了内建的特殊属性 Symbol.iterator,并返回一个「迭代器」。
举例来说,数组天生就是可迭代的:
const arr = [1, 2, 3];console.log(typeof arr[Symbol.iterator]); // 'function'Iterator
Iterator 必须通过 next 来进入下一个迭代,每次调用 next() 都会返回一个对象 { value, done },分别代表当前的值与是否结束:
const iterator = arr[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 }示例
可以自己定义一个可迭代的对象,例如一个「范围生成器」:
const range = { from: 1, to: 3, [Symbol.iterator]() { let current = this.from; const end = this.to; return { next() { if (current <= end) { return { value: current++, done: false }; } else { return { done: true }; } }, }; },};
for (const num of range) { console.log(num); // 1, 2, 3}Generator:更简洁的 Iterator 实作方式
上面的 range 虽然可行,但看起来有点繁琐。
Generator 函式提供了一种更直观的方式来建立迭代器。
function* range(from, to) { for (let i = from; i <= to; i++) { yield i; }}
for (const num of range(1, 3)) { console.log(num); // 1, 2, 3}Generator 是一种特殊的函数它并不会立即执行它内部的代码,可以在执行过程中「暂停」与「继续」,每次执行 yield 都会返回一个 { value, done } 结构的结果,改写先前案例:
function* threeStepGenerator() { yield 1; yield 2; yield 3; console.log('End');}
const gen = threeStepGenerator();console.log('Generator 已建立');
console.log(gen.next()); // { value: 1, done: false }console.log(gen.next()); // { value: 2, done: false }console.log(gen.next()); // { value: 3, done: false }console.log(gen.next()); // { value: undefined, done: true }总结
- Iterable:拥有
Symbol.iterator方法的对象。 - Symbol.iterator:具有
next()方法、能逐步返回{ value, done }的对象。 - Generator:通过
function*定义、内部使用yield产生值的语法糖,本质上自动帮你建立 Iterator。
实战上惰性求值、异步控制、数据流生成、协程模拟、迭代器封装都可以应用上相关概念。
延伸阅读
- JavaScript Iterators Explained with Examples | Level up Your JS - Ijemma Onwuzulike
- JavaScript Generators in 7 Minutes: What They Are and How They’re the Overpowered Iterator - Ijemma Onwuzulike
- Iterables - javascript.info
- Generators - javascript.info
- [Day 26] Lazy Evaluation 和 Generator Function - Monica