第七章:迭代器与生成器

第七章:迭代器与生成器

7.1 理解迭代

  • 最简单的迭代:for

7.2 迭代器模式

  • 可迭代对象:包含的元素有限,具有无歧义的遍历顺序
    • 不一定是集合对象

7.2.1 可迭代协议

  • 支持迭代的自我识别
  • 创建实现 Iterator 接口的对象的能力

7.2.2 迭代器协议

  • next()返回值:{ value: any, done: boolean }
  • 不同迭代器的实例之间没有联系
  • 对可迭代对象的修改会体现在迭代器上
// Test 类实现了可迭代接口(Iterable)
// 调用默认的迭代器工厂函数(Symbol.iterator),
// 会返回一个实现迭代器接口(Iterator)的迭代器对象
class Test {
    [Symbol.iterator]() {
        return {
            next() {
                return { done: false, value: 'test' };
            }
        };
    }
}

let t = new Test();
console.log(t[Symbol.iterator]());      // 打印出迭代器对象:{ next: [Function: next] }

7.2.3 自定义迭代器

  • 任何实现了 Iterator 接口的对象都可以作为迭代器使用
class Counter {
    constructor(limit) {
        this.limit = limit;
    }

    [Symbol.iterator]() {
        let count = 1;
        let limit = this.limit;
        return {
            next() {
                if (count <= limit) {
                    return { done: false, value: count++ };
                }
                else {
                    return { done: true, value: undefined };
                }
            }
        };
    }
}

let t = new Counter(3);
for (const child of t) {
    console.log(child);         // 1  2  3
}
  • 每个用这种方式创建的迭代器也实现了 Iterable 接口,会返回相同的迭代器(===)
let arr = [1, 2, 3, 4, 5];
let iter1 = arr[Symbol.iterator]();
let iter2 = iter1[Symbol.iterator]();

console.log(iter1 === iter2);   // true

console.log(iter1.next());      // { value: 1, done: false }
console.log(iter2.next());      // { value: 2, done: false }

7.2.4 提前终止迭代器

  • return()
    • 可选的 return()方法提前关闭迭代器。未关闭的迭代器下次会继续从中断的地方迭代
    • 并非所有迭代器都可以关闭
    • 调用该方法不会强制迭代器进入关闭状态

7.3 生成器

7.3.1 生成器基础

  • 箭头函数不能用来定义生成器函数
  • 星号不受两侧空格影响
function * generatorFn1() {

}

let generatorFn2 = function* () {}

let foo = {
    * generatorFn() {}
}
  • 调用生成器函数会产生一个生成器对象
    • 一开始处于暂停执行(suspended)状态
    • 该对象也实现了 Iterator 接口,具有 next()方法。调用该方法会让生成器开始或恢复执行
    • 该对象实现了 Iterable 接口,默认的迭代器是自引用的

7.3.2 通过 yield 中断执行

  • yield关键字可以让生成器停止或开始执行
  • yield不能位于嵌套的函数中
function* generatorFn() {
    yield 'a';
    yield 'b';
    return 'c';
}

let generator = generatorFn();
console.log(generator.next());      // { value: 'a', done: false }
console.log(generator.next());      // { value: 'b', done: false }
console.log(generator.next());      // { value: 'c', done: true }
1. 生成器对象作为可迭代对象
function* generatorFn() {
    yield 'a';
    yield 'b';
    yield 'c';
}

for (const x of generatorFn()) {
    console.log(x);                 // a  b  c
}
2. 使用 yield实现输入和输出
  • 第一次调用 next()传入的值不会被使用
3. 产生可迭代对象
  • 使用 yield*迭代一个可迭代对象。从而一次产生一个值
function* generatorFn() {
    yield* [1, 2, 3];
}

for (const x of generatorFn()) {
    console.log(x);                 // 1  2  3
}
4. 使用 yield*实现递归算法
function* generatorFn(n) {
    if (n > 0) {
        yield* generatorFn(n - 1);
        yield n - 1;

    }
}

for (const x of generatorFn(3)) {
    console.log(x);                 // 0  1  2
}

7.3.3 生成器作为默认迭代器

class Foo {
    constructor() {
        this.values = [1, 2, 3];
    }

    *[Symbol.iterator]() {
        yield* this.values;
    }
}

const f = new Foo();
for (const x of f) {
    console.log(x);     // 1  2  3
}

7.3.4 提前终止生成器

1. return()
  • 所有生成器对象都有该方法
2. throw()
  • 暂停的同时将提供的 error 注入生成器对象
    • 未被处理会关闭生成器
    • 内部进行了处理则会跳过对应的 yield
function* test() {
    for (const x of [1, 2, 3]) {
        try {
            yield x;
        }
        catch (e) {
            console.log(e);
        }
    }
}

const t = test();
console.log(t.next());  // { value: 1, done: false }
t.throw("foo");         // foo
console.log(t.next());  // { value: 3, done: false }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值