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) } // 吃飯 // 睡覺 // 打豆豆 // 語文 // 數學 // 外語 // 喝茶