20200419

@xiaojingzhao

Plan

  • 你不知道的 js 下卷 - 第三章 代码组织

Notes

迭代器

接口

Iterator:

  1. 有一个 next()方法返回 IteratorResult
  2. (optional)支持 return() -- 停止迭代器并返回 IteratorResult 和 throw() 方法 -- 报错并返回 IteratorResult

IteratorResult:

  1. value: 当前迭代的值或最终返回的值
  2. done: bool 指示完成状态

Iterable

  1. '@@iterator' 方法,生成一个迭代器

next() 迭代

数组

var a = [1, 2, 3];
var it = a[Symbol.iterator](); // 生成迭代器
var it2 = a[Symbol.iterator](); // 这是一个全新的迭代器
it.next();
// {value: 1, done: false}
it.next();
// {value: 2, done: false}
it.next();
// {value: 3, done: false}
it.next(); // 必须再次调用next才能得到完成的信号
// {value: undefined, done: true}

字符串也可以迭代

var greeting = "hello world";
var it3 = greeting[Symbol.iterator]();
it3.next(); // {value: "h", done: false}
// ...

return 和 throw

迭代器循环 -- for...of

迭代器不一定是 iterable 的,只有 iterable 的对象才能被 for...of。

是迭代器成为 iterable

var it = {
  [Symbol.iterator]() {
    return this;
  },
  next() {
    return; // ...
  },
};

for...of 中,如果出现了 {done: true},那么迭代就不会再继续发生。等价于:

for(var res; res = it.next() && !res.done) {
  // ...
}

所以当 next 返回最终值时,done 不能为 true。

自定义迭代器

无线斐波那契数列:

var fib = {
  n1: 0,
  n2: 0,
  [Symbol.iterator]() {
    return this;
  },
  next() {
    if (this.n1 === 0) {
      this.n1 = 1;
      return {
        value: 1,
        done: false,
      };
    } else if (this.n2 === 0) {
      this.n2 = 1;
      return {
        value: 1,
        done: false,
      };
    }
    [this.n1, this.n2] = [this.n2, this.n1 + this.n2];
    return {
      value: this.n2,
      done: this.n2 > 1000,
    };
  },
  return() {
    console.log("something happened!");
    return {
      value: undefined,
      done: true,
    };
  },
  throw() {
    console.log("something throwed!");
    return {
      value: undefined,
      done: true,
    };
  },
};

for (var next of fib) {
  if (next.value > 50) {
    break; // 并不会响应 break?
  }
  console.log(next);
}

for (var a of [1, 2, 3]) {
  if (a > 1) {
    break; // 正确的停止
  }
  console.log(a);
}

这里不知道为什么,自己定义的迭代器不能被 break?

迭代器消耗

'...' spread 运算符可以消耗迭代器

function foo(a, b, c, d) {
  //
}

foo(...[1, 2, 3, 4]); // 消耗

More