JavaScript高级程序设计笔记 7

第7章 迭代器与生成器 — 快速复习笔记

1. 迭代器(Iterator)

1.1 迭代器模式

  • 提供一种方法顺序访问集合中的每个元素,无需暴露底层结构。
  • JavaScript 中的迭代器是对象,必须实现 next() 方法。
  • next() 返回对象:{ value: any, done: boolean }
    • value:当前元素的值
    • done:是否迭代完成(true 表示结束)

1.2 可迭代协议(Iterable Protocol)

  • 要求对象实现 [Symbol.iterator] 方法,该方法返回一个迭代器。
  • 内置可迭代类型:ArrayStringMapSetargumentsNodeList 等。
  • 接收可迭代对象的语法:for-of... 扩展运算符、Array.from()、解构赋值等。
// 手动获取迭代器
let arr = [1,2,3];
let it = arr[Symbol.iterator]();
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

1.3 自定义可迭代对象

  • 为对象添加 [Symbol.iterator] 方法,返回带 next() 的对象。
let range = {
  from: 1,
  to: 5,
  [Symbol.iterator]() {
    this.current = this.from;
    return {
      next: () => {
        if (this.current <= this.to) {
          return { value: this.current++, done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};
for (let num of range) console.log(num); // 1 2 3 4 5

1.4 提前终止迭代器

  • 可选的 return() 方法:当迭代器提前退出时(如 breakthrow)调用。
  • 用于释放资源(如关闭文件、清除定时器)。

2. 生成器(Generator)

2.1 基础概念

  • 生成器是能返回生成器对象函数,可以暂停和恢复执行。
  • 定义:在 function 关键字后加 *function* generatorFn())。
  • 生成器对象既是迭代器也是可迭代对象

2.2 yield 关键字

  • 只能在生成器函数内部使用。
  • 遇到 yield 会暂停执行,并返回 yield 后的值(作为 next().value)。
  • 下一次调用 next() 从上次暂停处继续执行。
function* gen() {
  yield 1;
  yield 2;
  return 3; // 可选,done: true 时的 value
}
let g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: 3, done: true }

2.3 传参与 yield 表达式

  • next(param):参数会作为上一个 yield 表达式的返回值。
  • 第一个 next() 的参数会被忽略(因为没有上一个 yield)。
function* gen() {
  let a = yield 'first';
  console.log(a); // 接收第二次 next() 的参数
  let b = yield 'second';
  console.log(b);
}
let g = gen();
console.log(g.next());      // { value: 'first', done: false }
console.log(g.next(10));    // 10 赋值给 a,value: 'second'
console.log(g.next(20));    // 20 赋值给 b

2.4 yield*(委托生成器)

  • 用于在生成器中调用另一个生成器(或可迭代对象),逐个产出值。
function* gen1() {
  yield 1;
  yield 2;
}
function* gen2() {
  yield* gen1();
  yield 3;
}
for (let v of gen2()) console.log(v); // 1 2 3
// 等价于 yield* [1,2] 或 yield* "ab"

2.5 提前终止生成器

  • return():强制生成器进入关闭状态,done: true,后续 next() 无效。
  • throw():在生成器内部抛出错误,可被 try-catch 捕获。
function* gen() {
  try {
    yield 1;
    yield 2;
  } catch(e) {
    console.log('error caught');
  }
}
let g = gen();
console.log(g.next()); // { value: 1, done: false }
g.throw(new Error('boom')); // 输出 "error caught"

3. 内置可迭代 API

语法/API 说明
for-of 遍历可迭代对象
...(扩展运算符) 将可迭代对象转为数组
Array.from() 将可迭代对象转为数组
解构赋值 [a,b] = set 从可迭代对象中取值
Map/Set 构造函数 可接收可迭代参数
Promise.all() / Promise.race() 参数为可迭代对象

4. 应用场景

4.1 自定义迭代序列

  • 如斐波那契数列生成器
function* fibonacci() {
  let [prev, cur] = [0, 1];
  while (true) {
    yield cur;
    [prev, cur] = [cur, prev + cur];
  }
}
let f = fibonacci();
console.log(f.next().value); // 1
console.log(f.next().value); // 1
console.log(f.next().value); // 2

4.2 惰性求值

  • 只在需要时计算下一个值,节省内存。

4.3 异步流程控制(ES6 时代)

  • 配合 Promise 实现类似 async/await 的效果(现已很少手动实现)。

5. 常见面试题速查

  1. 什么是可迭代对象?
    → 实现了 [Symbol.iterator] 方法的对象,该方法返回一个迭代器。

  2. 迭代器与可迭代对象的区别?
    → 可迭代对象提供迭代器(通过 [Symbol.iterator]),迭代器是包含 next() 方法的对象。

  3. 如何判断一个对象是否可迭代?
    → 检查 typeof obj[Symbol.iterator] === 'function'

  4. for-offor-in 的区别?
    for-of 遍历可迭代对象的值;for-in 遍历对象可枚举属性(包括原型链)。

  5. 生成器函数与普通函数的区别?
    → 生成器函数调用时返回生成器对象,不会立即执行;可暂停(yield)和恢复。

  6. yieldreturn 在生成器中的作用?
    yield 暂停并返回值,return 终止生成器并设置 done: true

  7. yield* 的作用是什么?
    → 将迭代控制委托给另一个可迭代对象或生成器,逐个产出值。

  8. 生成器如何接收外部传入的值?
    → 通过 next(param),参数会成为上一个 yield 表达式的返回值。

  9. 如何提前终止生成器?
    → 调用 return()throw()

  10. 生成器能否实现无限序列?
    → 可以,只要循环中没有结束条件,每次 next() 都会产生下一个值。

posted @ 2024-04-10 09:36  Li_pk  阅读(5)  评论(0)    收藏  举报