第七章 迭代器与生成器
迭代器
基本使用方法
迭代器只是使用游标来记录遍历的对象,如果可迭代对象在迭代期间修改了,迭代器也会反映出对应的变化
1 2 3 4 5 6 7
| let arr = ['foo', 'bar'] let it = arr[Symbol.iterator] console.log(it.next()) arr.splice(1, 0, 'baz') console.log(it.next()) console.log(it.next()) console.log(it.next())
|
自定义迭代器
实现Iterator接口的对象都可以作为迭代器使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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 counter = new Counter(3) for (let i of counter) { console.log(i) }
|
提前终止迭代器,自定义终止时需要执行的方法,调用return并不会强制迭代器进入关闭状态,即后面的遍历会接着上次的遍历结果
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 29
| class Counter { [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 } } }, return() { console.log('exit early') return { done: true } } } } } let counter = new Counter(3) for (let i of counter) { if (i > 2) { break; } console.log(i) }
let [a, b] = counter
|
生成器
基本使用方法
在函数名称前加*号,来表示它是一个生成器,生成器也实现了Iterator接口,可以进行for…of迭代
1 2 3 4
| function* generator() {} let foo = { * generatorFn() {} }
|
使用yield中断执行
1 2 3 4 5 6 7 8 9
| function* generatorFn() { yield 'foo' yield 'bar' return 'baz' } let it = generatorFn() console.log(it.next()) console.log(it.next()) console.log(it.next())
|
使用yield输入输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function* generatorFn() { return yield 'foo' } let it = generatorFn() console.log(it.next()) console.log(it.next('bar'))
function* generatorFn() { yield* [1, 2, 3] }
function generatorFn() { for (const x of [1, 2, 3]) { yield x } }
|
生成器作为默认迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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) }
|
提前终止生成器
return()
return()方法会强制生成器进入关闭状态,只要进入关闭状态,就无法恢复了,后续调用next()会显示done:true状态,for-of循环等会忽略状态为done:true时的IteratorObject内部返回的值
1 2 3 4 5 6 7
| function* generatorFn() { yield* [1, 2, 3] } let g = generatorFn() console.log(g) console.log(g.return(4)) console.log(g)
|
throw()
throw()方法会在暂停时将一个错误注入到生成器对象中,如果错位未被处理,则生成器就会关闭,处理了错误,则会跳过那一次执行的结果
1 2 3 4 5 6 7 8 9 10 11
| function* generatorFn() { for (const x of [1, 2, 3]) { try { yield x } catch(e) {} } } let g = generatorFn() console.log(g.next()) g.throw('foo') console.log(g.next())
|
generator/yield实现async/await
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 29 30 31 32 33 34 35 36 37 38 39 40 41
| function _aync(fn) { const context = this return new Promise((resolve, reject) => { if (typeof fn === 'function') fn = fn.call(this) if (!fn || typeof fn.next !=== 'function') return resolve(fn) onFullFilled() function onFullFilled(ret) { let val try { val = fn.next(ret) } catch(e) { reject(e) } next(val) } function onRejected(err) { let val try { val = fn.throw(err) } catch(e) { reject(e) } next(val) } function next(ret) { if (ret.done) return resolve(ret.value) let value = ret.value if (!isPromised(value)) { value = Promise.resolve(value) } return value.then(onFullFilled, onRejected) } function isPromised(obj) { Object.prototype.toString.call(obj) === '[object Promise]' } }) }
|