# 迭代器与生成器

# 1、迭代器原理

可迭代对象指的是任何具有专用迭代器方法,且该方法返回迭代器对象的对象。迭代器对象指的是任何具有 next()方法,且该方 法返回迭代结果对象的对象。迭代结果对象是具有属性 value 和 done 的对象。

要迭代一个可迭代对象,首先要调用其迭代器方法获得一个迭代器对象。然后,重复调用这个迭代器对象的 next()方法,直至返回 done 属性为 true 的迭代结果对象。

可迭代对象的迭代器方法没有使用惯用名称,而是使用了符号 Symbol.iterator 作为名字。

const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
for (let i of iterator) {
  console.log(i);
}
// 1
// 2
// 3

// 执行迭代
console.log(iter.next()); // { done: false, value: 1 }
console.log(iter.next()); // { done: false, value: 2 }
console.log(iter.next()); // { done: false, value: 3 }
console.log(iter.next()); // { done: true, value: undefined }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2、实现可迭代对象

class Foo {
  [Symbol.iterator]() {
    return {
      next() {
        return { done: false, value: 'foo' };
      },
      // 指定在迭代器提前关闭时执行的逻辑
      return() {
        console.log('early end');
        return { done: true };
      },
      // 让迭代器本身也可迭代
      [Symbol.iterator]() {
        return this;
      },
    };
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3、生成器

function* gFn() {
  yield 1;
  yield 2;
  yield 3;
}

// 调用生成器函数,得到一个生成器
const g = gFn();
g.next(); // 1
g.next(); // 2
g.next(); // 3

// 在类和字面量中简写
const o = {
  x: 1,
  y: 2,
  *g() {
    yield 3;
    yield 4;
  },
};

[...o.g()] // => [3, 4]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

注意,不能使用箭头函数语法定义生成器函数。

# 3.1 生成器函数的返回值

function* oneAndDone() {
  yield 1;
  return 'done';
}

// 正常迭代中不会出现的返回值
[...oneAndDone()] // => [1]

// 显式调用 next() 可以得到
const g = oneAndDone()
g.next() // => { value: 1, done: false }
g.next() // => { value: 'done', done: true }
g.next() // => { value: undefined, done: true }
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.2 yield 表达式的值

yield是一个表达式(回送表达式),可以有值

function* smallNum() {
  console.log('第一次调用,参数被丢弃')
  const y1 = yield 1; // y1 === 'b'

  console.log('第二次调用,参数是', y1)
  const y2 = yield 2; // y1 === 'c'

  console.log('第三次调用,参数是', y2)
  const y3 = yield 3; // y1 === 'd'

  console.log('第四次调用,参数是', y3)
  return 4;
}

const g = smallNum()
console.log('创建了生成器,代码未运行')

const n1 = g.next('a') // n1.value === 1
console.log('生成器回送', n1.value)

const n2 = g.next('b') // n2.value === 2
console.log('生成器回送', n2.value)

const n3 = g.next('c') // n3.value === 3
console.log('生成器回送', n3.value)

const n4 = g.next('d') // n4.value === { value: 4, done: true }
console.log('生成器回送', n4.value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

注意以上代码是不对称的。第一次调用next()启动生成器,但传入的值无法在生成器中访问到。

上次更新: 2/21/2023, 9:39:49 PM