迭代器
什么是迭代器
js迭代器是一个对象,具有next方法,可以返回序列中的带有done和value两个属性的下一项。
function makeIterator(array){ var nextIndex = 0;4 return { next: function(){ return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {done: true}; } }; }
迭代器接口
可迭代对象如Map,Set,Array,String,arguments,DOM elements的实例拥有一个名为Symbol.iterator的接口函数,调用该函数会返回迭代器
let a = [1,3,4] var b = a[Symbol.iterator]() console.log(b + '') //[object Array Iterator] console.log(b.next()) //{ value: 1, done: false } console.log(b.next()){ value: 3, done: false } console.log(b.next()){ value: 4, done: false } console.log(b.next()){ value: undefined, done: true }
拥有该接口函数的,可以使用for of
循环,优点是可以使用break,只会遍历可迭代对象。
for (let i of a) { console.log(i) }
输出1,3,4
还可以使用展开运算符,yield*以及结构赋值
生成器
function*
function* 可以生成generator生成器对象。函数在调用generator的next方法时才会运行,运行到yield处会暂停,注意,会把yield处的语句执行。等到下一个next方法运行时才继续执行,
调用 next()方法时,如果传入了参数,那么这个参数会作为上一条执行的 yield 语句的返回值,例如:
function *gen(){ yield 10; y=yield 'foo'; yield y; } var gen_obj=gen(); console.log(gen_obj.next());// 执行 yield 10,返回 10 console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo' console.log(gen_obj.next(10));// 将 10 赋给上一条 yield 'foo' 的左值,即执行 y=10,返回 10 console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true
generator生成器对象
生成器对象即是可迭代对象又是迭代器,由generator function返回,具有next方法和return方法。
next方法可以获得下一项
function* gen() { yield 1; yield 2; } let g = gen() g.next() console.log(g.next()) // {value:1,done: false} console.log(g.next()) // {value:2,done: false} console.log(g.next()) // {value:undefined,done: true}
return结束迭代。
console.log(g.return()) // {value:undefined,done: true}
实战
斐波那契数列
function* fibo() { let a = 0 let b = 1 yield a yield b while (true) { let next = a + b a = b b = next yield next } } let generator = fibo() for (var i = 0; i < 10; i++) console.log(generator.next().value) //=> 0 1 1 2 3 5 8 13 21 34 55
异步
一个每次调用加10的函数。可以看出,gen函数中的写法是同步的风格,然而实际上t函数中用到了异步,这里用到了yield的暂停和重新启动功能,十分强大。
const gen = function*(num) { console.log(num) var a = yield t(num) console.log(a) var b = yield t(a) console.log(b) return b }; var genResult = gen(10); genResult.next() function t (num) { setTimeout(() => { genResult.next(num + 10) }, 100) }
输出10,20,30
跟promise结合
function t (num) { return new Promise(res => res(num + 10)) } function runGenerator(g, ...res) { var it = g(...res), ret; (function iterate(val){ ret = it.next( val ); if (!ret.done) { if ("then" in ret.value) { ret.value.then( iterate ); } else { setTimeout( function(){ iterate( ret.value ); }, 0 ); } } })(); } runGenerator(gen, 30)