es6 新增了Generator函数,一种异步编程的解决方案
回顾一下,es6 提供了新的遍历方法,for of ,适用于各种数据集合,统一了遍历操作,原生支持for of 集合的数据集合有。数组,字符串
一部分的类数组,map,set。而对象是不适合与 for of 遍历的,因为原生没有实现Iterator接口,而手动的为对象添加Iterator接口,我们之前使用
return next() 操作,而今天我们尝试用Generator 函数去实现对像的Iterator接口,
// Generator 函数实现对象的 Iterator接口 // 定义一个简单的对象 let obj = { a: '12344444', b: '333444', c: 'dddddd', d: 'meiy' } // 在 for of 学习中我们知道,要想使用for of 遍历 我们需要给对象实现Symbol.iterator接口 // Generator 函数的定义是function* ,每次调用Generator.next() 会执行函数内部的yeild obj[Symbol.iterator] = function* () { let keys =Object.keys(this) // Object.keys 得到的对象属性集合可以直接使用for of for(let key of keys) { yield [key,this[key]] } } // 上面对象的Iterator接口已经定义完成下面我们使用for of 循环遍历 for(let item of obj) { console.log(item) }
// 结果
[ 'a', '12344444' ]
[ 'b', '333444' ]
[ 'c', 'dddddd' ]
[ 'd', 'meiy' ]
定义后Genertation函数后,我们可以像调用普通函数一样,使用()去调用,但是Generator函数直接调用是不会执行的,我们必须掉用
Generator函数next()使其执行,执行到第一个yeild ,放回一个对象{value:'',done:false} ,如果对象已经执行完,则返回{value:'',done:true},如果还继续
掉用next()方法则返回{value:undefined,done:true},Generator 除了next()外,还有两个操作,分别是throw(),return();(注,yeild 只能用于Generator内部)
// Generator 函数 next() return() throw()
// 让我们先定义一个简单的Generator函数
function* gen() {
console.log('开始了')
yield 1
yield 2
yield 3
return 4
}
// 当我们使用()去掉用时gen函数数,并不执行
let g = gen() // 不会输出开始了 注,Generator 不能使用new 去实例,会报错
console.log(g.next()) // 输出 开始了 { value: 1, done: false } 执行到第一个yeild处
console.log(g.next()) //{ value: 2, done: false }
console.log(g.next()) //{ value: 3, done: false }
console.log(g.next()) //{ value: 4, done: true } //执行完 则done 放回ture
// 如果没有最后一个return ,放回值就是undefined
//next() 函数可以传入一个参数,作为上一个yeild 的返回值
function* fhz (x) {
let y = yield x +1
let z = yield y + 12
return y+z
}
let zx = fhz(5);
console.log(zx.next()) // 执行第一个 yeild 表达式,返回6
// 执行第二个yeild 表达式,第一个yeild并未传值进去,则y时undefined
//console.log(zx.next()) // undefined+12 =>> Nan
console.log(zx.next(2)) // 14
console.log(zx.next(1)) // 3
// 上一步执行完,y = 2 这一步,传入的是1 未yeild y+12的值,也是z的值,所有最终输出3
Generation throw()方法
// Generator throw() function* throws() { try { yield 2 } catch (ex) { console.log('th'+ex) } } let th = throws(); th.next() //只有调用了next Generator 内部才能执行 th.throw() //thundefined try { th.throw('我该') // 内部已经没有catch 则访问外部的catch } catch (err) { console.log('12',err) } function* jdd() { throw new Error('不多不少') yield 33; //前面抛出了 throw 这里就不会再执行了 } let sj = jdd() try { sj.next() } catch (err) { console.log(err) } try { console.log(sj.next()) } catch (err) { console.log(err) }
Generation return 函数
// Generator return() function* fn () { yield 1 yield 2 yield 3 yield 4 return 67 } let f = fn() console.log(f.return()) // { value: undefined, done: true } 因为未传入参数,返回的就是undefined console.log(f.return(123)) // { value: 123, done: true } rerutn 后函数就不执行了 // 但如果函数内部有try finally 则直接会跳转到执行finally 内部 function* finna () { try { yield 1 yield 2 yield 3 } finally { yield 4 yield 5 } return 6 } let fina = finna() console.log(fina.next()) //{ value: 1, done: false } console.log(fina.return()) // 使用return,执行 执行yeild 4 console.log(fina.next()) //执行yeild 5 console.log(fina.next()) //执行,fina.return() console.log(fina.next()) //{ value: undefined, done: true }