Senior Syntax —— 高级语法编程
Scene Pratice —— 案例dom
ES5
循环一旦执行,没法停下来的异步
function loop() { for(let i = 0; i < 5; i++) { console.log(i) } } loop() // 0 // 1 // 2 // 3 // 5
使用Generator
,怎么改造?异步编程
// 修改一,在loop前面加一个星号 function * loop() { for(let i = 0; i < 5; i++) { // 修改二:在输出前面加yield yield console.log(i) } } // 修改三:定义一个变量将loop赋值给l const l = loop() // 这个时候并无输出,若要输出调用next方法 l.next() // 0 l.next() // 1 l.next() // 2 l.next() // 3 l.next() // 4 l.next() // 以后不会输出任何东西 //应用场景:年会抽奖、自定义遍历器
yield
停下来next
控制循环Generator
函数的定义不能使用箭头函数,不然会出发报错SyntaxError
function * gen() { let val val = yield 1 console.log(val) } const l = gen() // "Generator { }" l.next() // 没有任何输出 l.next() // undefined yield表达式没有返回值,因此返回undefined
next()
的返回值函数
第一个参数是返回的值,oop
第二个参数是是否遍历完成,false
是没有遍历完,true
是遍历完成学习
function * gen() { let val val = yield [1, 2, 3] console.log(val) // undefined } const l = gen() console.log(l.next()) // {value: Array(3), done: false} console.log(l.next()) // {value: undefined, done: true}
function * gen() { let val // yield 后面加了一个星号,后面是一个遍历的对象,因此能够嵌套一个Generator对象 val = yield * [1, 2, 3] console.log(val) // undefined } const l = gen() console.log(l.next()) // {value: 1, done: false} console.log(l.next()) // {value: 2, done: false}
学到这里要明白:this
Generator
是作什么用的?<br/>控制循环流程用的<br/>
最重要的做用是解决异步编程嵌套层级较深的问题。spa
yield
有没有返回值?<br/>没有,可是遍历器对象的
next
方法能够修改这个默认值code
- 和
ES5
相比,是如何控制程序的中止和启动的?<br/>使用
yield
去控制中止,使用next
去控制启动
如何在函数外部控制函数内部的运行?
next
函数写参数,做为yield
的返回值
function * gen() { let val val = yield [1, 2, 3] console.log(val) // 20 } const l = gen() console.log(l.next(10))// {value: Array(3), done: false} // 此时yield没有赋值,因此10并无用 console.log(l.next(20))// {value: undefined, done: true} // 此时yield对val进行赋值操做,yield表达式的值是20
讲义的例子能够理解更深入
function * gen() { var val = 100 while(true){ console.log(`before${val}`) val = yield val console.log(`return ${val}`) } } let g = gen() console.log(g.next(20).value) // before 100 // 100 console.log(g.next(30).value) // return 30 // before 30 // 30 console.log(g.next(40).value) // return 40 // before 40 // 40
1.g.next(20)
这句代码会执行gen
内部的代码,遇到第一个yield
暂停。因此console.log("before "+val)
执行输出了before 100
,此时的val
是100
,因此执行到yield val
返回了100
,注意yield val
并无赋值给val
。2.
g.next(30)
这句代码会继续执行gen
内部的代码,也就是val = yield val
这句,由于next
传入了30
,因此yield val
这个返回值就是30
,所以val
被赋值30
,执行到console.log("return "+val)
输出了30
,此时没有遇到yield
代码继续执行,也就是while
的判断,继续执行console.log("before "+val)
输出了before 30
,再执行遇到了yield val
程序暂停。3.
g.next(40)
重复步骤2
。
function * gen() { let val val = yield [1, 2, 3] console.log(val) // 没有执行 } const l = gen() console.log(l.next(10))// {value: Array(3), done: false} console.log(l.return())// {value: undefined, done: true} //返回操做,函数终止 console.log(l.next(20))// {value: undefined, done: true}
添加返回值的参数
function * gen() { let val val = yield [1, 2, 3] console.log(val) // 没有执行 } const l = gen() console.log(l.next(10))// {value: Array(3), done: false} console.log(l.return(100))// {value: 100, done: true} //返回操做,函数终止 console.log(l.next(20))// {value: undefined, done: true}
function * gen() { while (true) { try { yield 1 } catch (e) { console.log(e.message) // ss } } } const l = gen() console.log(l.next())//{value: 1, done: false} console.log(l.next())//{value: 1, done: false} console.log(l.next())//{value: 1, done: false} l.throw(new Error('ss')) // 抛出错误,执行catch console.log(l.next()) //{value: 1, done: false}
ES5
function draw (first = 1, second = 3, third = 5) { // 三个奖的候选人,一个结果,一个随机数 let firstPrize = ['1A', '1B', '1C', '1D', '1E'] let secondPrize = ['2A', '2B', '2C', '2D', '2E', '2F', '2G', '2H', '2I', '2J', '2K', '2L'] let thirdPrize = ['3A', '3B', '3C', '3D', '3E', '3F', '3G', '3H', '3I', '3J', '3K', '3L', '3M', '3N', '3O', '3P', '3Q', '3R', '3S', '3T', '3U', '3V', '3W', '3X', '3Y', '3Z'] let result = [] let random // 抽一等奖 for(let i = 0; i < first; i++){ random = Math.floor(Math.random() * firstPrize.length) result = result.concat(firstPrize.splice(random, 1)) } // 抽二等奖 for(let i = 0; i < second; i++){ random = Math.floor(Math.random() * secondPrize.length) result = result.concat(secondPrize.splice(random, 1)) } // 抽三等奖 for(let i = 0; i < third; i++){ random = Math.floor(Math.random() * thirdPrize.length) result = result.concat(thirdPrize.splice(random, 1)) } return result } console.log(draw()) // ["1A", "2D", "2K", "2A", "3A", "3G", "3Y", "3W", "3P"]
ES6
function * draw (first = 1, second = 3, third = 5) { // 三个奖的候选人,一个结果,一个随机数 let firstPrize = ['1A', '1B', '1C', '1D', '1E'] let secondPrize = ['2A', '2B', '2C', '2D', '2E', '2F', '2G', '2H', '2I', '2J', '2K', '2L'] let thirdPrize = ['3A', '3B', '3C', '3D', '3E', '3F', '3G', '3H', '3I', '3J', '3K', '3L', '3M', '3N', '3O', '3P', '3Q', '3R', '3S', '3T', '3U', '3V', '3W', '3X', '3Y', '3Z'] let count = 0 let random while(1){ if (count < first) { random = Math.floor(Math.random() * firstPrize.length) yield firstPrize[random] count ++ firstPrize.splice(random, 1) } else if (count < first + second) { random = Math.floor(Math.random() * secondPrize.length) yield secondPrize[random] count ++ secondPrize.splice(random, 1) } else if (count < first + second + third) { random = Math.floor(Math.random() * thirdPrize.length) yield thirdPrize[random] count ++ thirdPrize.splice(random, 1) } else { return false } } } let d = draw() console.log(d.next().value) // 1C console.log(d.next().value) // 2E console.log(d.next().value) // 2H console.log(d.next().value) // 2C console.log(d.next().value) // 3H console.log(d.next().value) // 3V console.log(d.next().value) // 3A console.log(d.next().value) // 3J console.log(d.next().value) // 3N console.log(d.next().value) // false console.log(d.next().value) // undefined console.log(d.next().value) // undefined
若是是ES5,是无限死循环,程序崩溃
ES6
function * count (x = 1) { while (1) { if (x % 3 === 0) { yield x } x++ } } let num = count() console.log(num.next().value) // 3 console.log(num.next().value) // 6 console.log(num.next().value) // 9 console.log(num.next().value) // 12 console.log(num.next().value) // 15 console.log(num.next().value) // 18 ...
const todos = { life: ['吃饭', '睡觉', '打豆豆'], learn: ['语文', '数学', '外语'], work: ['喝茶'], each: function (callback) { const all = [].concat(this.life, this.learn, this.work) for( const item of all) { callback(item) } }, [Symbol.iterator]: function * () { const all = [...this.life, ...this.learn, ...this.work] for(const item of all) { yield item } } } for(const item of todos){ console.log(item) } // 吃饭 // 睡觉 // 打豆豆 // 语文 // 数学 // 外语 // 喝茶