红宝书读书笔记 第七章

迭代器和生成器

https://segmentfault.com/a/1190000010747122
写的足够好

迭代器模式

把有些结构成为可迭代对象(iterable),因为它们实现了正式的iterable接口,而且可以通过迭代器iterator消费
迭代器是按需创建的一次性对象。每个迭代器都会关联一个可迭代对象,而迭代器会暴露迭代其关联可迭代对象的API。迭代器无序了解与其关联的可迭代对象的结构,只需要知道如何取得连续的值。

可迭代协议

实现iterable接口(可迭代协议)要求具备的两种能力:
支持迭代的自我识别能力和创建实现iterator接口的对象的能力。这意味着必须暴露一个属性作为默认迭代器,而这个属性必须使用特殊的Symbol.iterator作为键。这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器

Array 、 string \ set \ map \ argumengs\nodelist等均是可迭代

let num = 1;
console.log(num[Symbol.iterator])//undefined
这种方式可以检测是否迭代

接受可迭代对象的原生语言特性:

for of
数组结构
扩展操作符
Array.from()
创建集合
创建映射
Promise.all()
Promise.race()
yield*

如果对象原型链上的父类实现了iterable接口,那么这个对象也实现这个接口

class Foo extends Array {}
let foo = new Foo('foo','bar')
for(let el of foo) {
    
}

迭代器协议

迭代器是一种一次性使用的对象,迭代与其关联的可迭代对象。迭代器API使用next()方法遍历数据,每次返回一个IteratorResult对象,其中包含迭代器的下一个值
迭代器不知道可迭代对象多大

提前终止迭代器

return()必须返回一个有效的IteratorResult对象,可以只返回{done: true}

class Counter {
    constructor(limit) {
        this.limit = limit;
    }
    [Symbol.iterator]() {
        let count = 1,
            limit = this.limit;
        return {
            next() {
                if(count <= limit) {
                    return {done: false, value: count++}
                } else {
                    return {done: true};
                }
            },
            return() {
                console.log('exit early')
                return {done: true}
            }
        }
    }
}
let counter1 = new Counter(5)
for(let i of counter1) {
    if(i > 2) {
        break;
    }
    console.log(i);
}
输出
1
2
exit early
只要break就exit early,与console无关


break  countinue  return throw  结构操作
均可以实现提前退出
例如
let [a,b] = [1,2,3]

return()并不强制迭代器进入关闭状态,所以可以继续使用迭代器

let a = [1,2,3,4,5]
let iter = a[Symbol.iterator]();
iter.return = function () {
    console.log('exit')
    return {done: true}
}
for(let i of iter) {
    console.log(i)
    if(i>2)break;
}
for(let i of iter) {
    console.log(i)
}

IteratorResult对象包含两个属性done 和 value

生成器

生成器拥有在一个函数块内暂停和恢复代码执行的能力。

生成器基础

调用生成器函数会产生一个生成器对象。生成器对象一开始处于暂停执行(suspended)状态。生成器对象也实现iterator接口,具有next()方法。
next()返回值有一个done和value属性

yield

上面链接对基础内容介绍已经足够
yield只能在生成器函数内部使用

function* valid() {
    yield;//ok
}

function* invalid() {
    function a() {
        yield;//无效
    }
}

生成器显示调用next()用处不大,但可以把生成器对象当做可迭代对象

function *gene() {
    yield 1;
    yield 2;
    yield 3;
}
for(const x of gene()) console.log(x)

星号可以增强yield,使它能够迭代一个可迭代对象,从而一次产出一个值

yield*的值是关联迭代器返回done:true时的value属性。对于普通迭代器来说,这个值是undefined

function* gener() {
    console.log('iter:',yield* [1,2,3])
}
for(const x of gener()) {
    console.log('value:' ,x )
}
输出
value: 1
value: 2
value: 3
iter: undefined

对于生成器函数产生的迭代器,这个值就是生成器函数返回的值

function *inner() {
    yield 'foo';
    return 'bar'
}
function *outer(genObj) {
    console.log('iter',yield *inner())
}
for(const x of outer()) {
    console.log('value:',x)
}
输出
value: foo
iter bar

yield*实现递归

function *nTimes(n) {
    if(n > 0) {
        yield * nTimes(n - 1)
        yield n - 1;
    }
}
for (const x of nTimes(3) ) {
    console.log(x)
}

提前终止生成器

return() throw() 都可以提前终止生成器
二者可以用于强制生成器进入关闭状态

function* gener() {
    for(const x of [1, 2, 3]) {
        yield x;
    }
}
const g = gener();
console.log(g)
console.log(g.return(4))
console.log(g)

所有生成器都有return()方法,通过它进入关闭状态,就无法恢复了

function *gener() {
    for (const x of [1, 2, 3]) {
        yield  x;
    }
}
const g = gener();
for (const x of g) {
    if (x > 1) {
        g.return(4)
    }
    console.log(x)
}
输出
1
2

throw()
throw()方法会在暂停的时候将一个提供的错误注入到生成器对象中。如果错误未被处理,生成器就会关闭。
如果错误在生成器函数内部处理了,就不会关闭,还可以恢复执行。错误处理会跳过对应的yield
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值