for…of 循环

for...of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。

  1. function* foo() {
  2. yield 1;
  3. yield 2;
  4. yield 3;
  5. yield 4;
  6. yield 5;
  7. return 6;
  8. }
  9. for (let v of foo()) {
  10. console.log(v);
  11. }
  12. // 1 2 3 4 5

上面代码使用for...of循环,依次显示 5 个yield表达式的值。这里需要注意,一旦next方法的返回对象的done属性为truefor...of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for...of循环之中。

下面是一个利用 Generator 函数和for...of循环,实现斐波那契数列的例子。

  1. function* fibonacci() {
  2. let [prev, curr] = [0, 1];
  3. for (;;) {
  4. yield curr;
  5. [prev, curr] = [curr, prev + curr];
  6. }
  7. }
  8. for (let n of fibonacci()) {
  9. if (n > 1000) break;
  10. console.log(n);
  11. }

从上面代码可见,使用for...of语句时不需要使用next方法。

利用for...of循环,可以写出遍历任意对象(object)的方法。原生的 JavaScript 对象没有遍历接口,无法使用for...of循环,通过 Generator 函数为它加上这个接口,就可以用了。

  1. function* objectEntries(obj) {
  2. let propKeys = Reflect.ownKeys(obj);
  3. for (let propKey of propKeys) {
  4. yield [propKey, obj[propKey]];
  5. }
  6. }
  7. let jane = { first: 'Jane', last: 'Doe' };
  8. for (let [key, value] of objectEntries(jane)) {
  9. console.log(`${key}: ${value}`);
  10. }
  11. // first: Jane
  12. // last: Doe

上面代码中,对象jane原生不具备 Iterator 接口,无法用for...of遍历。这时,我们通过 Generator 函数objectEntries为它加上遍历器接口,就可以用for...of遍历了。加上遍历器接口的另一种写法是,将 Generator 函数加到对象的Symbol.iterator属性上面。

  1. function* objectEntries() {
  2. let propKeys = Object.keys(this);
  3. for (let propKey of propKeys) {
  4. yield [propKey, this[propKey]];
  5. }
  6. }
  7. let jane = { first: 'Jane', last: 'Doe' };
  8. jane[Symbol.iterator] = objectEntries;
  9. for (let [key, value] of jane) {
  10. console.log(`${key}: ${value}`);
  11. }
  12. // first: Jane
  13. // last: Doe

除了for...of循环以外,扩展运算符(...)、解构赋值和Array.from方法内部调用的,都是遍历器接口。这意味着,它们都可以将 Generator 函数返回的 Iterator 对象,作为参数。

  1. function* numbers () {
  2. yield 1
  3. yield 2
  4. return 3
  5. yield 4
  6. }
  7. // 扩展运算符
  8. [...numbers()] // [1, 2]
  9. // Array.from 方法
  10. Array.from(numbers()) // [1, 2]
  11. // 解构赋值
  12. let [x, y] = numbers();
  13. x // 1
  14. y // 2
  15. // for...of 循环
  16. for (let n of numbers()) {
  17. console.log(n)
  18. }
  19. // 1
  20. // 2