摘要:始最近的業余時間在看相關的書也在極客時間上買了前端相關的專欄對于一個非的人來說時時會有一種感覺社區是真的激進和浮燥這幫規則的制定者似乎從來也不知道克制為何物有很多時候固有的東西是可以處理好的但是偏偏喜歡人為制造一些概念和語法糖人為的建起一座
始
最近的業余時間在看 js 相關的書, 也在極客時間上買了前端相關的專欄, 對于一個非 jser 的人來說, 時時會有一種感覺: js 社區是真的激進和浮燥, 這幫規則的制定者似乎從來也不知道克制為何物. 有很多時候固有的東西是可以處理好的, 但是偏偏喜歡人為制造一些概念和語法糖, 人為的建起一座又一座的高山, 似乎你沒跨過就是個 "菜雞"
請原諒我的惡毒, 看《js 語言精粹》的時候, 這種感覺非常的強烈. 作者是業內的大牛, 還制定了 json, 但是每一章還在最開頭引一句莎翁的話, "似乎無關緊要又暗藏哲理". 書中很多內容要表達的意思總有一種: 明明可以將話說成 10 分讓一個普通人都能看得明白的, 卻偏不, 只說 6 分, 剩下的自己去悟, 有很多規則性的東西并非是靠悟, 而是靠幾句話說清楚其本質就豁然開朗的.
換成以前, 會覺得這人是一座好大的高山要進行膜拜, 這幾年雖然自己技術依然不那么好, 但是還是喜歡去思考一些內在的東西, 更在努力一點一點把心里的權威崇拜給去掉, 再看到這些的時候, "..." 這幾個標點符號很容易印在腦子里. 感覺這不只是一兩個人這樣, 極有可能是整個 js 圈子都是這樣
說回標題上來, 除了看書, 看專欄, 找資料, 很久都還是沒有把 generator 和 async/await 給理解透, 于是自己試著整個梳理了一下運行的流程
Generator我先試著在 yield 后面不跟任何的東西, 可以直接復制到控制臺輸出
function *f0(param) { console.log("n: " + param); yield; console.log("i"); let l = yield; console.log("l: " + l); } let v0 = f0("p"); console.log(v0.next(1)); // 輸出 n: p 和 {value: undefined, done: false} console.log("----"); console.log(v0.next(2)); // 輸出 i 和 {value: undefined, done: false} console.log("----"); console.log(v0.next(3)); // 輸出 l: 3 和 {value: undefined, done: true} console.log("----"); console.log(v0.next(4)); // 輸出 {value: undefined, done: true} console.log("----"); console.log(v0.next(5)); // 輸出 {value: undefined, done: true}
在上面的基礎上給方法 return 值
function *f1() { console.log("n"); yield; console.log("i"); let l = yield; console.log("l: " + l); return "?"; } let v1 = f1(); console.log(v1.next(1)); // 輸出 n 和 {value: undefined, done: false} console.log("----"); console.log(v1.next(11)); // 輸出 i 和 {value: undefined, done: false} console.log("----"); console.log(v1.next(111)); // 輸出 l: 111 和 {value: "?", done: true} console.log("----"); console.log(v1.next(1111)); // 輸出 {value: undefined, done: true} console.log("----"); console.log(v1.next(11111)); // 輸出 {value: undefined, done: true}
然后我試著在 yield 的后面加上內容
function *f2(param) { console.log("0: " + param); let f = yield 1; console.log("1: " + f); let s = yield f + 2; console.log("2: " + s); let t = yield (s + 3); console.log("3: " + t); let fo = (yield s) + 4; console.log("4: " + fo); } let v2 = f2("p"); console.log(v2.next("N")); // 輸出 0: p 和 {value: 1, done: false} console.log("----"); console.log(v2.next("I")); // 輸出 1: I 和 {value: "I2", done: false} console.log("----"); console.log(v2.next("L")); // 輸出 2: L 和 {value: "L3", done: false} console.log("----"); console.log(v2.next("S")); // 輸出 3: S 和 {value: "L", done: false} console.log("----"); console.log(v2.next("H")); // 輸出 4: H4 和 {value: undefined, done: true} console.log("----"); console.log(v2.next("I")); // 輸出 {value: undefined, done: true} console.log("----"); console.log(v2.next("T")); // 輸出 {value: undefined, done: true}
最后, 在上面的基礎上給方法 return 值
function *f3() { console.log("0"); let y1 = yield 1; console.log("1: " + y1); let y2 = yield y1 + 2; console.log("2: " + y2); let y3 = yield (y2 + 3); console.log("3: " + y3); let y4 = (yield y3) + 4; console.log("4: " + y4); return "??"; } let v3 = f3(); console.log(v3.next("N")); // 輸出 0 和 {value: 1, done: false} console.log("----"); console.log(v3.next("I")); // 輸出 1: I 和 {value: "I2", done: false} console.log("----"); console.log(v3.next("L")); // 輸出 2: L 和 {value: "L3", done: false} console.log("----"); console.log(v3.next("S")); // 輸出 3: S 和 {value: "S", done: false} console.log("----"); console.log(v3.next("H")); // 輸出 4: H4 和 {value: "??", done: true} console.log("----"); console.log(v3.next("I")); // 輸出 {value: undefined, done: true} console.log("----"); console.log(v3.next("T")); // 輸出 {value: undefined, done: true}
大致上就清楚 yield 的運行邏輯了, 以上面的 f3 為例, 對照上面的輸出來看, 它其實是將一個方法分成了這樣幾段來執行
// 下面 五行一起的豎線(|) 用一個大括號表示出來會更直觀一點 function *f3() { // 調用 next("N") 時運行的代碼 console.log("0"); let y1 = yield 1; return 1; // | 封裝成 {value: 1, done: false} 返回 // | // | 這兩行等同于 let y1 = yield 1; // 調用 next("I") 時運行的代碼 // | let y1 = "I"; // | console.log("1: " + y1); return y1 + 2; // | 封裝成 {value: "I2", done: false} 返回 // | // | 這兩行等同于 let y2 = yield y1 + 2; // 調用 next("L") 時運行的代碼 // | let y2 = "L"; // | console.log("2: " + y2); return (y2 + 3); // | 封裝成 {value: "L3", done: false} 返回 // | // | 這兩行等同于 let y3 = yield (y2 + 3); // 調用 next("S") 時運行的代碼 // | let y3 = "S"; // | console.log("3: " + y3); return (y3); // | 封裝成 {value: "S", done: false} 返回 // | // | 這兩行等同于 let y4 = (yield y3) + 4; // 調用 next("H") 時運行的代碼 // | let y4 = ("H") + 4; // | console.log("4: " + y4); return "??"; // 封裝成 {value: "??", done: true} 返回 // done 為 true 之后, 再 next() 就都返回那一個了 }
再回頭想一想就知道了, 第一次運行 next("N") 的時候, 傳進去的 N 是會被忽略的, 因為第一次 next() 傳的值沒有 yield 前面來接收. 再去看書也好, 看查到的文章也好, 第一次 next() 都是沒有傳過參數
感覺 yield 就是為了迭代而生的, 迭代完全可以就用 for 啊, 但是卻繞成這樣, 也不知道這是為哪般! 就這還能新弄一個 for of 玩出花來, 因為每執行 next() 才會執行那一段段, 還美其名曰 "咱們終于可以異步了"
async/await再是 es7 開始有的這倆關鍵字, 看了一個大廠的面試題, 自己為了加深對這兩個關鍵字的理解改了一下成下面這樣
async function async1() { console.log("A"); console.log(await async2()); return "B"; } async function async2() { console.log("C"); return "D"; } console.log("E"); setTimeout(function() { console.log("F"); }, 0); async1().then(function(r) { console.log(r); }); new Promise(function(resolve, reject) { console.log("G"); resolve(); }).then(function() { console.log("H"); }); console.log("I");
在 chrome 73.0.3683.75 底下的輸出是:
// 這個 undefined 的意思應該主要是用來分隔宏任務的, 也就是前面的主線和任務隊列是在一起的 E A C G I D H B undefined F
在 firefox 60.5.1 底下的輸出
// 這個 undefined 的意思應該只是用來分隔主線的, 任務隊列和宏任務在一起了 E A C G I undefined H D B F
在 opera 58.0.3135.107 底下的輸出是:
// 這個 undefined 應該跟 chrome 里面是一樣的 E A C G I H D B undefined F
明顯 D H B 是比較合理的. 在 firefox 和 opera 的實現中明顯是有問題的, 想像得到, 低版本一點的 chrome 也可能是后面的結果
終還有像 var let const 這種一個簡單的賦值都能玩出這么多花樣(當然, 這可以說是歷史遺留問題導致的)
老實說, 我覺得這更多是為了: "別的語言有, 咱們這么前衛的語言當然應該要有!"
...
就這么樣一門語言, 居然可以流行成現在這樣, 只能說這個世界是真奇妙
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102704.html
摘要:迭代器是一種特殊對象,每一個迭代器對象都有一個,該方法返回一個對象,包括和屬性。默認情況下定義的對象是不可迭代的,但是可以通過創建迭代器。在迭代器中拋出錯誤不再執行生成器返回語句生成器中添加表示退出操作。迭代器是一個對象。 迭代器(Iterator) ES5實現迭代器 迭代器是什么?遇到這種新的概念,莫慌張。 迭代器是一種特殊對象,每一個迭代器對象都有一個next(),該方法返回一個對...
摘要:在年正式發布了,簡稱,又稱為。再次簡寫循環迭代數組每個元素都執行一次回調函數。方法用于調用數組的每個元素,并將元素傳遞給回調函數。注意對于空數組是不會執行回調函數的。 轉載請注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關系。ECMA是標準,Jav...
摘要:在年正式發布了,簡稱,又稱為。再次簡寫循環迭代數組每個元素都執行一次回調函數。方法用于調用數組的每個元素,并將元素傳遞給回調函數。注意對于空數組是不會執行回調函數的。 轉載請注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關系。ECMA是標準,Jav...
摘要:常用知識總結之前總結了中的一些知識點。在年正式發布了,簡稱,又稱為。作為構造函數的語法糖,同時有屬性和屬性,因此同時存在兩條繼承鏈。子類的屬性,表示構造函數的繼承,總是指向父類。 ES6常用知識總結 之前總結了es5中js的一些知識點。這段時間看了石川blue老師講解的es6課程,結合阮一峰老師的es6教程,隨手做了一些筆記和總結分享給大家。內容還是es6主要的知識點,基本沒有什么創新...
閱讀 4913·2023-04-25 18:47
閱讀 2673·2021-11-19 11:33
閱讀 3445·2021-11-11 16:54
閱讀 3101·2021-10-26 09:50
閱讀 2540·2021-10-14 09:43
閱讀 665·2021-09-03 10:47
閱讀 671·2019-08-30 15:54
閱讀 1499·2019-08-30 15:44