# 第四次 ###### tags: `課程` :::spoiler TODOs :::warning #### TODOs ##### javascript - [x] history - [] interpret language (may bey too much) - [] Chrome V8 engine - [] Just In Time Compiler - [ ] relatives: es6, commonjs, typescript, coffescript - [x] Variable - [x] Types - [x] week typing language - [x] var v.s. let - [x] Functions - [x] anonymous function - [x] arrow function - [ ] Object Orentied - [ ] prototype - [x] key:value - [x] this keyword - [x] export - [ ] Concurrency - [x] callback - [ ] async ##### Others ###### Mongoose - [ ] schema - [ ] model - [ ] document ###### Some express thing - [ ] router - [ ] app.js - [ ] package.js ::: ::: :::info 由於它內容實在是太多太深奧,我盡量講點我懂的東西,以及比較可能會讓人困惑的東西 ::: ``` ^ ^ ( OwO) |m |m b b ``` # 奇怪的 JavaScript ## 歷史系! :fire: ### Browser - 1995年 Netscape 的 Brendan Eich 設計了第一版的 "JavaScript" - 1997年 Netscape 向 ECMA International歐洲國際標準組織提交 JavaScript,產生了初版的 ECMAScript 草案,自此 ECMAScript 成為標準規範 - 2003年 - Netscape 解散,並開放程式碼 - Miscrosoft 反壟斷法敗訴 - Apple 加入戰局,使用開源專案 "渲染引擎 Webkit" ,釋出 Safari - 2004年 Mozilla 繼承 Netscape 程式碼釋出 Firefox - 2008年 Google 釋出 Chrome,使用 Webkit 與自行研發的 "V8-engine" - chrome 核心:Chromium 以開源專案的方式釋出 - 2012年 Chrome 與 IE 產生死亡交叉 - 2015年 Microsoft 發布 Edge - 2018年 Microsoft 發布 Chromium 版 Edge - 2021年 Microsoft 決定方棄 IE - To Be Continue... ### require vs import 一種功能兩種寫法 https://github.com/seajs/seajs/issues/588 https://ithelp.ithome.com.tw/articles/10191478 ### 居然!? - 據說第一板的設計只花了 10 天 - 取做 "javascript" 的原因是因為想要蹭當時超人氣語言 Java 熱度 - `Node.js` 是使用 V8-engine 來執行 JavaScript 程式碼的 - V8 engine 是用 C++ 寫的 ### 歷史影響 ECMA 只負責定規格,至於怎麼實做(引擎)則是開發者自己想辦法 > [相關文章](https://ithelp.ithome.com.tw/articles/10191345) ## 程式語言特性 > 難,可以不用太在意這一段 > 這段基本上可以跳過 ### Interpreter language - 不會直接變成執行檔,需要用一個 interpreter 解釋執行原程式碼 - 不會像 C 那樣要先變成一個執行檔再執行它 - 所以其實 JavaScript 是被另一個程式來模擬執行的 - firefox, chrome, safari, 等內部都有各自的 javascript engine ### Week typing - variable 型態隨時都可以被改變 ```javascript= let a; a = 1.0; // the typeof a is Number a = 'OwO'; // the typeof a is String ``` :::success Week typing 與 Strong typing 不是非黑及白的分類,而比較像是一種線性的分佈 e.g. Week typing <--- `JavaScript`--`python`--`C` ---> Strong typing ::: ### JIT (Just In Time Compiler) V8-engine 中有 Just In time Compiler, 當執行 JavaScript 程式時,若途中發現有一段程式碼不斷的被執行很多遍,便會啟動 JIT 多花一點的時間將這段程式碼用更優化的方式翻譯,並緩存起來以便下次使用。 基於這樣的 JIT 的機制導致 JavaScript 雖然是直譯語言但是仍然有不錯的執行效率。 ### Garbege collection 用不到的 variable 會在一段時間後被刪掉 ## Variable ### Declaration 總共有三種不同的宣告方法:`var`, `let`, `const` #### Hoisting ```javascript= console.log(a); // 可以正常使用,output: undefined var a = 1; ``` ```javascript= console.log(a); // error: Uncaught ReferenceError: Cannot access 'a' before initialization let a = 1; ``` ```javascript= console.log(a); // error: Uncaught ReferenceErro: Cannot access 'a' before initialization const a = 1; ``` `var` 這種宣告方是會有 _Hoisting_ 的現象,變數會像是被 “提前” 一樣,在被宣告的那一行之前就能使用。這是因為 Node.js 在執行 JavaScript code 時會有兩個階段:_Parsing_ 與 _Executing_ _Parsing_ 階段會掃過一遍確認有哪些 variable/function declaration (確認有 變數/函式 是存在的) 而 _Executing_ 時再確實執行他們 > 注:這邊的階段分的很隨意,實際上有更複雜的階段與細節,這裡不詳述,因為我也不會 ```javascript= // Paring console.log(a); var a = 1; // <- 找到 declaration var a; // <- a 已經被宣告過,無視 console.log(a); --------------------------------- // Executing console.log(a); // a 還未初始化,值為:"undefined" a = 1; // 把變數 a 中裝入 1 console.log(a); // 這就會印出 1 了 ``` `let` 與 `const` **不會**有 _Hoisting_ 的現象,使用 `let` 和 `const` 宣告的變數會在執行才被宣告,因此重複宣告是會報錯的。 ```javascript= console.log(let_variable); // let_variable 未宣告,程式 爆 error, crush let let_variable; // <- 不會在 Parse 階段被掃到 ``` :::danger :no_entry_sign: 不建議使用 `var`,因為他可能會導致程式便的很難 debug 譬如: ```javascript= var myVariable = 10; // 你的程式碼 ... ... var myVariable = 11; // 別人後來更新的程式碼,變數名剛好也取做 `myVariable` ... ... console.log(myVariable); // 你的程式碼 ``` 這樣程式仍然能運作,但是你負責的那一塊卻變的怪怪的了,然後你想破頭也不知道到底為什麼會這樣。 如果大家都使用 `let` 就可以避免這個問題了。因為會直接爆掉說那裡錯了。 ::: #### `const` : constant `const` 也就是 constant。當你希望設一個不會改變的變數時就可以設成 `const`,避免有哪個小王八蛋(~~自己~~)想改變他。只要有人想改他程式就會直接原地爆破。 ```javascript= const pi = 3.141592653589793; ... pi = 100; // TypeError: Assignment to constant variable. ``` #### 小結 - `var`: - 會 Hoisting - 可以重複宣告不會報錯 - ~~混沌邪惡~~ - `let`: - 跟其他語言比較接近的使用方式 - ~~守序中立~~ - `const`: - 常數 - ~~絕對中立~~ > 查看更多: > - [MDN Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting) > - [更詳細的](https://www.freecodecamp.org/news/javascript-execution-context-and-hoisting/) ### Scope 變數有他的使用範圍,過了使用範圍就無法使用它了。 這樣的設計是問了讓你可以不用整天去煩惱一堆人撞名的問題。 ```javascript= let x = 1; while (true) { let x = 2; // 這個二號 x 只存在於 whlie 迴圈內 console.log(x); // 2 break; } console.log(x); // 1, 這邊的 x 指的是一號 x function foo() { let x = 3; // 這個三號 x 也只存在於 foo() 內 } function bar() { x = 100; // 由於 bar() 內沒有 x,所以需要往外找,因此這個 x 是一號 x } ``` 變數 scope 基本上就是在一個 _Code Block_ 裡(可以當成兩個大括號內的程式碼區) :::warning #### 注意 :heavy_exclamation_mark: `var` 在 Scope 上有個例外,`function` 可以把 `var` 分開來 但是 `var` 可以穿透 `while`, `for` 等程式區塊。 ```javascript= for (var x = 0; x < 10; x++) { } console.log(x); // x 可以透出來! ``` 不過你如果不用 `var` 了話也不太會有這樣的問題就是了 ::: ### Type JavaScript 的 Type 可以分為兩種: _Primitive_ 與 _Object_ - Primitive type - Number - String - Booleam - Null - Undefine > pay attension to the `null` and `undefine`. it may make you program crush - Object - Function - > 是的在 JavaScript 中 Function 也是一種變數型態! - Array - Number - String - Booleam - Date - ... ::: spoiler 奇異的小知識 :::success #### 奇異的小知識 :open_book: - 在 V8-engine 的實做(C++)中,一個 variable 事實上只有三種型態 `int`, `double`, `pointer` 其他型態是模擬出來的。 - Array 其實背後有分`int array`, `double array`, `object array` - 在新增元素時,若目前的型態不支援便會轉型 ::: :::success #### 更奇異的小知識 - `NaN`: Not a Number 是一種 Number - 如果呼叫 `typeof null` 它會說是 `object'. ```javascript= typeof NaN; // Number typeof null; // object ``` > reference: [你懂 JavaScript 嗎?#4 型別(Types](https://cythilya.github.io/2018/10/11/types) ![](https://thumbs.gfycat.com/TenderFormalIndianglassfish-size_restricted.gif) ::: 在 JavaScript 中,一個變數的型態可以不斷的改變 ```javascript= let a; // undefine a = 1; // number a = 'aa'; // string a = [1, 2, 'b']; // object (Array) ``` ### primitive vs object > primitive is immutable primitive type 就是那些基礎型態的東西,而且他們是 immutable 的 注意: 你不能“修改” primitive 的值,但是可以改變 variable 中裝的 primitive 值 ```javascript= let a = 1; b = a; ``` ```graphviz digraph { node [shape="record"] a [label="a|1"] b [label="b |1"] } ``` > object is kind of referencing or pointer 一個 Object 可以擁有自己的 method 與 attribute。 一個 variable 不會 “裝著” object 而是 reference 到 object (可以姑且當成是“指著”) ==這裡是重點!== ```javascript= let v1 = [1, 2, 3]; let v2 = v1; // v2 並沒有 copy v1,而是 reference 到跟 v1 同一個 object v2[2] = 4; console.log(v1); // 會變成 [1, 2, 4] ``` ```graphviz digraph { node [shape="record"] v1 [label="v1|<p> "] v2 [label="v2|<p> "] subgraph cluster_heap { label="Heap" data [label="[1, 2, 3]"] } v1:p -> data v2:p -> data } ``` :::info #### 腦荊棘轉彎 ==TODO: 有點問題== 猜猜看以下的 code 會發生什麼事情 ```javascript= function swap(x, y) { let temp = x; x = y; x = temp; } let a = 1, b = 2; swap(a, b); let o1 = [1, 2]; let o2 = [2, 3]; swap(o1, o2); ``` :::spoiler 答案 ```graphviz digraph { node[shape="record"] a [label="a |<p> 1"] b [label="b |<p> 2"] subgraph cluster_swap { label="function swap" x [label="x | 1"] y [label="y | 2"] } } ``` ```graphviz digraph { label="一開始" node[shape="record"] o1 [label="o1 |<p>"] o2 [label="o2 |<p>"] subgraph cluster_swap { label="function swap" x [label="x |<p>"] y [label="y |<p>"] } subgraph cluster_heap { label="heap" data1 [label="[1, 2]"] data2 [label="[2, 3]"] } o1:p -> data1 o2:p -> data2 x:p -> data1 y:p -> data2 } ``` ```graphviz digraph { label="after some operation in function" node[shape="record"] o1 [label="o1 |<p>"] o2 [label="o2 |<p>"] subgraph cluster_swap { label="function swap" x [label="x |<p>"] y [label="y |<p>"] } subgraph cluster_heap { label="heap" data1 [label="[1, 2]"] data2 [label="[2, 3]"] } o1:p -> data1 o2:p -> data2 x:p -> data2 y:p -> data1 } ``` ::: ::: :::warning #### 其他: 如果用 ```javascript= let a = new Number(); ``` 的寫法妳會得到一個 object 裡面裝著 number。他跟 primitive 的 number 是不太一樣的 ::: </br> ### Very Very Strange Comparison ![](https://miro.medium.com/max/640/1*opN7wHJG5ITFYXcCvS7LUg.jpeg =500x) 在使用 `==` 時,兩邊的值會被轉型同一種型態後在進行比較 而 `===` 才會比較兩者的 type - 非嚴格比較:`==`, `!=` - 嚴格比較:`===`, `!==` :::danger 除非你要做奇怪的事情,不然盡量用 `===` ! ::: > [`==` 的對照表](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Equality_comparisons_and_sameness) ## Objects > [w3c school](https://www.w3schools.com/js/js_objects.asp) 當我們寫程式時,有時會想要操作一些“物件”。這時我們就可以使用 object 的概念。 :::info info: 在不同的地方在討論 object 時會出現一些名詞像是: _attribute_, _property_, _class member_ 其實他們指的概念都差不多。 javascript 中 通常稱呼為 _property_ ::: ```javascript= // 可以單純當成一個資集合來操作 let car = { // object 內容可以當成很多對的 key:value color: 'Red', // color 就是 car 的一個 property weight: 100, } car.color = 'Blue'; car.speed = 48763; // javascript 允許直接增加 property ``` ### `this` 在 object method 中用來指稱自己的 keyword ```javascript= let car = { color: 'Red', weight: 100, beep: function() { console.log(this.color); // 此處的 this 即為呼叫他的人:car } } car.beep(); // 執行 beep method ``` > ![](https://memes.tw/user-template/b3e1d929769a64110e80703fc1a6945c.png =400x) > 其實它還有其他更複雜的細節,好奇了話可以看這篇文章 > [淺談 JavaScript 頭號難題 this](https://blog.techbridge.cc/2019/02/23/javascript-this/) ### Prototype > 難,可以不用太在意 JavaScript 中沒有像 Java 那樣的 `class` 寫法。取而代之的則是 Prototype 與 object 系統。 > [prototype chain](https://github.com/aszx87410/blog/issues/18) ## function 你可以宣告一段可以重複使用的程式碼段! ```javascript= // 注意: javascript function 不會在意你到底放了什麼東西進來 // 因此它得實際行為可能會跟你想得不一樣! function add(a, b) { return a + b; } let c = add(1, 2); // 3 let d = add('a', 1) // 'a1' let e = add(add(1, 2), 'a') // '3a' ``` ### anonymous function 沒有名子的 function ```javascript= // 將沒有名子的 function 存到 foo 裡面 (foo 指向它) let foo = function(a, b) { console.log(a + b); } foo(1, 2); // 3 // 原地執行 (function () { console.log(a + b); })(1, 2); ``` ### arrow function 無名 function 的簡化寫法 ```javascript= let foo = (a, b) => { console.log(a + b); } foo(1, 2); // 3 ``` > arrow function 唯一的差別在於 `this` 的判定方式,細節可以去上面 this 的文章 > 難,可以不用在意這個小區別 ### call back 既然我們可以把 function 裝進 variable 裡,那我們也可以把 function 作為另一個 function 的 input ```javascript= function executeB(a, b) { b(a); } function b1(a) { console.log(a + 1); } executeB(1, b1); // 2 executeB(1, (a)=> { console.log(a + 1); }); // 2 ``` 為什麼要這樣寫? 因為在 JavaScript 裡常常會有想要某個 function 在特定的時候被觸發,像是: server 接到 request 的時候,browser 的使用者點擊某個按鈕的時候。 ```javascript= let handler = (req, res) { ... } router.get('/hello', handler); // express 在接到對 'hello' 的request 時,就會再去執行 handler // router.get('url', callback); // router.get('/hello', (req, res) => { // res.send(req.body.msg); // }) ``` ## Promise > 跳過ㄇ.... 為了解決 callback hell,為了 Async 的和平 可愛又迷人的 Promise then ! catch ! finally ! ## Concurrency Pain peko > [講的非常非常清楚明瞭的影片](https://www.youtube.com/watch?v=8aGhZQkoFbQ) > [一篇文章](https://blog.sessionstack.com/how-javascript-works-event-loop-and-the-rise-of-async-programming-5-ways-to-better-coding-with-2f077c4438b5) ## Module 由於一開始 js 並不支援 Module 的使用,於是民間便自幹了一套 Module 系統。 稱作: common.js 而後過了一段時間後,EJS 才正式的發表了 `import` 的使用方法。 因此 JavaScript 中有兩種主流的 Module 使用方式 > [相關文章](https://ithelp.ithome.com.tw/articles/10191478) ```javascript= // myModule.js function add(a, b) { return a + b; } // module.exports 就是到時候 require 時會回傳的東西 module.exports = add; ``` ```javascript= // main.js const addFunction = require('myModule'); console.log(addFunction(1, 2)); // 3 ``` > 另外的 `export`/`import 語法我就不再這邊介紹了` ## Helpful links - [wiki](https://zh.wikipedia.org/zh-tw/JavaScript) - [w3cschool](https://www.w3schools.com/js/default.asp) - [es6 優質大文章](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/) - [How javasciprt work: part1](https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf) - [How javascript work: part2](https://blog.sessionstack.com/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e) - [youtube: 關於v8機ㄓ](https://www.youtube.com/watch?v=UJPdhx5zTaw) - [GeekofGeeks: variable](https://www.w3schools.com/js/js_let.asp) - [MDN Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting) - [高難度 Hoisting](https://github.com/aszx87410/blog/issues/34) - [JavaScript comparison](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Equality_comparisons_and_sameness) - [解釋 javascript 執行流程](https://www.youtube.com/watch?v=8aGhZQkoFbQ) - [concurrency 講的非常非常清楚明瞭的影片](https://www.youtube.com/watch?v=8aGhZQkoFbQ) - [concurrency一篇文章](https://blog.sessionstack.com/how-javascript-works-event-loop-and-the-rise-of-async-programming-5-ways-to-better-coding-with-2f077c4438b5) - [prototype chain](https://github.com/aszx87410/blog/issues/18)