#### Introduction to JavaScript ![](https://i.imgur.com/F6jIklH.png) Spring 2019 。 Ric Huang --- 在學習完 HTML & CSS 之後, 你應該是有能力可以刻出一個靜態網頁 (雖然 CSS 的 state selector 也是可以做出一定程度的動態網頁啦!) --- 現代的動態網頁 (各種跟使用者 I/O 的互動), 幾乎都是使用 JavaScript 寫的 但為了接下來理解如何 利用 JavaScript 製作出動態網頁, 我們必須先瞭解何謂 **DOM (Document Object Model)** --- ### DOM (Document Object Method) ([wiki](https://en.wikipedia.org/wiki/Document_Object_Model)) …is a cross-platform and language-independent application programming interface that treats an HTML, XHTML, or XML document as a tree structure wherein each node is an object representing a part of the document. --- ![](https://i.imgur.com/0BwgCFO.png) --- ### Let's HACK it! ![](https://i.imgur.com/OkP3ar6.png) ---- * 開啟[台大校長室首頁](https://www.ntu.edu.tw/administration/president.html) * 打開 **開發人員選項 -> 檢視元素** * 滑鼠在頁面滑動,看是否可以看得出 DOM structure? * 滑到管校長玉照,click on its parent \<div> element (有看到旁邊多了一個 $0 嗎?) * 打開 "console", 輸入 $0 試試看! * (先到網路上選一張圖片,複製連結) 輸入 $0.innterHTML = "<img src='你的圖片連結'... 照著原先的打" * (選到 "校長 管中閩博士" 的 \<p>) 用 $0.innterText 改改看! --- ## Did you really HACK it?? --- ### Not really... 剛剛改的是你瀏覽器(前端)收到的 HTML (i.e. local 端),一但 reload, 從 server 端 (i.e. 台大計中) 重新載入網頁,剛剛的修改就都不見了! --- 不過,如果你寫了一個網頁服務程式,放在自己的伺服器,讓使用者在他的瀏覽器進行互動的過程中 (如:滑鼠點按、填資料送出等),將「動作」送至伺服器,然後你的網頁程式「聽到」這個動作「事件」後,送回對應的網頁更新(部分)腳本,使用者就會看到更新的網頁了! --- ### JavaScript 就是去 listen event <br>來操作 DOM 的內容,<br>以達到動態網頁的目的 --- ### 不過,在介紹JavaScript語法之前,<br>讓我們來了解一下 JavaScript 精彩的(黑)[歷史](https://auth0.com/blog/a-brief-history-of-javascript/) * Possibly the most hated language in the world ---- ### A new web language was born * Year 1995 (rise of IE; Netscape/Sun/Microsoft) * Brendan Eich created it in a few weeks * 披著 Java 皮,流著 Scheme (first-class function) / Self (prototype-based)的血 ---- ### 醜小鴨變天鵝 * 短時間生產出來的畸形兒 * ECMA standardization (ES): 1 (1997), 2 (1998) * ES3: the first big change (1999) * ES4: the unborn child * ES3.1 (2008) -> ES5 (2009) ---- ### ES6 (aka. ES 2015): The Modern JS * let/const * arrow function * class * promise (to relieve callback hells) * generator * binary/octal literals ---- ### ES7 and Beyond * ES7 (aka. ES 2016) * minor changes (e.g. exponential **) * ES2017 * async/await (to improve "promise") * shared memory and atomics * ES2018 * asynchronous iteration * generator arrow functions ---- ### What's next? * Inter-platform operability * Native support on VM * (Already is) Full-stack language --- ### JavaScript。與 C++ 比較 ---- ### 相異之處 * 弱型別,所有的變數都是 var (or let/const) ```javascript var a = “38”; var b = false; console.log(a + !b); ``` * Statement 的後面可以不用加 “;” * 數字都是 “double“ ```javascript 0.1 + 0.2; // = 0.30000000000000004 ``` * 除了 ==, 還有 === * 字串可以用 ' ' or " " ---- ### Prototype-Based object construction 不用先定義 class 即可建置物件,且一旦一個物件被建置好,後續的物件可以用它來當作原型來建置類似的物件 ---- ### First-Class Functions 也就是說 functions 被當成是一般的變數(物件),可以當成其他 function 的參數或是回傳值,也可以被 assigned 給別的變數 --- ### JavaScript Basics * console.log() * Types/Variables/Objects * Function * Array * Control statements * DOM manipulation & Event listening --- ### console.log * 是你 debug 的好朋友,會將訊息印在 “console” (e.g.) In Chrome on Mac, press “command-option-i” ```javascript var a = 1; console.log(a); ``` --- ### Types/Variables/Objects * JavaScript 只有五種內建型別(primitive types),**其他都是物件(objects)** | 型態 | 範例 | |-----| ---- | | Undefined (未定義) | undefined | | Null (空值) | null | | String (字串) | "哎呀" | | Boolean (布林值) | true, false | | Number (數字) | 3.1415926 | ---- ### In JS, almost everything is an object * Object in JavasScript is represented as: ```javascript { property: value, ... } ``` ```javascript var me = { name: "Ric", age: 18 } ``` * Note: No need to define "type" or "var" for "name" and "age" ---- ### 三種產生 object 的方法 1. Object literal ```javascript var a = { name:"Ric", score:100 }; ``` 2. “new” operator ```javascript var b = new Date; ``` 3. Constructor function ```javascript function Student(name, score) { this.name = name; this.score = score; } var c = new Student(“Ric”, 100); // return this ``` * What happens for “var d = Student(“Nacy”, 20);”? // The returned type of Student() is "undefined" ---- ### 不要把五種內建型別宣告成 object ```javascript var a = new Number(3); // 不建議 var b = Number(3); // What's the difference? console.log(a === b); // false ``` ```javascript var a = 3; // a is a primitive var b = Number(3); // b is a primitive var c = new Number(3); // c is an object ``` ---- ### The keyword “Object” defines an object ```javascript var o = new Object; ``` ---- ### “prototype-based” object construction ```javascript var o = new Object; console.log(o); // No need to define "name" and "score" in advance o.name = "Ric"; o.score = 100; var o2 = new Object; console.log(o); console.log(o2); ``` ---- #### Primitive variable assignment makes a “copy” ```javascript var a = 3; var b = a; // {a, b} = {3, 3} b = 4; // {a, b} = {3, 4} a = 5; // {a, b} = {5, 4} ``` ---- #### Object variable assignment pass the “reference” to the object’s address ```javascript var i = { a:3 }; var j = i; j.a = 4; // i.a = 4 i.a = 5; // j.a = 5 ``` --- ### Function as an Object * Functions in JavaScript is “first-class” // Function as an object (i.e. constructor function) * var f = function add(a, b) { return a + b; }; * Note: Function 的 arguments 沒有必要加上 “var” NOT "function add(var a, var b)" * Function can be anonymous // recommended ```javascript var add = function(a, b) { return a + b; }; ``` ---- ### Function assignment * 如同 object assignment (i.e. pass by reference) ```javascript // f is an reference to add var f = function add(a, b) { return a + b; }; // print out the returned value of f(3,4) console.log(f(3,4)); // print out f itself console.log(f); // Error (why?) console.log(add); ``` ---- ### Return of a function * By default, the return value of a function is "undefined", unless call by "new" (return this) ```javascript var f = function(a, b) { return a + b; }; f(3,5); f(f(1,2),3); ``` ---- ### Return a function ```javascript var f = function(s) { return s? function(a,b) { return a+b; }: function(a,b) { return a-b; } }; var f1 = f(true); f1(3,5); var f2 = f(false); f2(3,5); ``` ---- ### Methods in Objects * Recall: prototype-based object construction ```javascript var a = { name:"Ric", score:100 }; a.gender = "Male"; ``` * Since function is also an object, we can define “method functions” in an object as: ```javascript var a = { name:"Ric", score:100, report: function() { return this.name + " got " + this.score; } }; a.report(); // Ric got 100 ``` ---- ### Define a method afterwards ```javascript a.isPass = function() { console.log(this.score >= 60? “Yes”: “No”); }; a.isPass() // Yes ``` ---- ### Immediately Invokable Function Expression * When a function is used only once, we can declare it anonymously and evoke it immediately ```javascript (function() { ... some statements })(); ``` --- ### Test yourself #1 (Any errors?) ```javascript= function f(a) { console.log(a); } f(0); var b = f; b; b(10); b("Hello"); var c = f(20); c; // undefined c(30); // Error! ``` ---- ### Test yourself #2 (Any errors?) ```javascript= var f = function add(a, b) { return a + b; }; add(10, 20); // Error! f(20, 30); var g = f; g(30, 40); var h = add; // Error! h(40, 50); // Error! ``` ---- ### Test yourself #3 (Any errors?) ```javascript= var f = function add(a, b) { return a + b; }; var g = add; // Error var h = function add(a, b) { return a + b; }; var i = function add(a, b, c) { return a + b + c; }; var f = "Hello"; // overloading f ``` ---- ### Test yourself #4 (Any errors?) ```javascript= var f = function pp() { ... } var g = f; var f = function qq() { ... } console.log(f); // qq console.log(g); // pp ``` --- ## Array Objects ---- ### To define an array 1. Using array literal ```javascript var students = [ "John", "Mary", "Ric" ]; ``` 2. Using new Array // not recommended ```javascript var students = new Array("John", "Mary", "Ric"); ``` ---- ### Data in an array can be of any types ```javascript var a = [ "Ric", 100, function() { return "Hello!"; } ]; a[2](); // Hello! ``` ---- ### ”length” property and “push” method in Array ```javascript // initialized as an empty array var s = [ ]; s.push("John"); // recommended s[s.length] = "Mary"; // length is now 2 s[3] = "Ric"; // OK, but create an “undefined” in [2] ``` ---- ### Array is a special kind of object ```javascript var students = [ "John", "Mary", "Ric" ]; typeof students; // object Array.isArray(students); // true ``` ---- ### Array elements MUST BE accessed by numbers * 雖然一些 object 的行為看起來很像 array, 但嚴格來說,他們是不一樣的 ```javascript var a = { name:"Ric", score:100 }; a["name"]; // "Ric" a[0]; // undefined Array.isArray(a); // false ``` ---- ### Array or Object * Array is an object. ```javascript var s = []; s[0] = "John"; s["Name"] = "Ric"; console.log(s); // ["John", name: "ric"] Array.isArray(s); // true ``` --- ### Control statements in JavaScript are pretty much the same as in Java/C/C++ * Comparison in JavaScript use "=\==" and "!\==" * "==" 跟 "!=" 會雞婆地幫你做型別轉換 "5" == 5; // = true null == undefined; // = true * 更多令人崩潰的型別轉換/比較會在下一章補充 --- ### Variable Hoist * Variable 定義的位置會自動抬升到最前面 * 以下兩種寫法是一樣的(雖然前者不太正常): ```javascript a = 1; var a = 2; ``` ```javascript var a = 1; a = 2; ``` ---- ### Function Hoist * Function declaration 定義的位置會被抬升到最前面 ```javascript sum(3,5); // This is OK! function sum(a, b) { return a + b; }; ``` * 但用 expression 定義的 function 變數則不會被抬升 => 如果在定義之前就被使用,就會是 error ```javascript sum(3,5); // Error var sum = function(a, b) { return a + b; }; ``` --- ### Variable Scope * 事實上,“var” 沒有寫也會過,只是會被視為全域變數 (global variable) * 此外,”var” 如為區域變數,其範圍並非 block, 而是 function scope ```javascript function() { for (var i = 0; i < 10; i++) console.log(i); } // 等同於 function() { var i; for (i = 0; i < 0; i++) console.log(i); } ``` ---- ### Variable Scope * 在同一個範圍內重複用 “var” 宣告同名字的變數,後者會被無視,而只進行 assignment ```javascript var a = 0; { var a = 10; } // 仍屬同一範圍之 'a'. a = 10 now var b = function() { var a = 20; } b(); // local 'a' 並非 global 'a'. 所以 a 仍然為 10 ``` --- ### ”let” and “const” * 2015 年發表的 ES6 版本加入了 “let” 跟 “const” ---- ### “let” 跟 C/C++ 的變數一樣,採取 block scope * 同一個 scope 不能宣告相同名稱的變數 * 不能在宣告變數之前就使用 (i.e. 用 let 宣告的變數不會被抬升 (hoist) 到 scope 的最前面) * 在 global scope 用 let 宣告的變數並不是真正的 global variable ==> 並不會變成 “window” 這個全域物件底下的屬性,因此,像是用 module 載入的程式碼並看不到這個 global scope 的 let 變數 ---- ### “const” 亦跟 C/C++ 一樣,表示 “read-only” 的常數變數 * 養成習慣,多多使用 const --- ### DOM Manipulations * 選擇節點 * 瀏覽節點 * 增減節點 * 修改節點內容 * 事件監聽綁定 ---- #### 在一個瀏覽器的頁面 “window” 是唯一的全域物件,<br>而 “document” 是它的一個屬性 ![](https://i.imgur.com/noVFr80.png) #### 如前所述,所謂的動態網頁就是在 event 觸發之後,選擇某個/某些 DOM 節點,然後改寫其內容或是周邊的節點 (node/element) --- ### 選擇節點 * 從 top level (i.e. “document”) 尋找 DOM nodes ```htmlembedded <div id="target"></div> <div class="a-class"></div> ``` 1. 回傳 unique DOM node ```javascript var target = document.getElementById("target"); ``` 2. 回傳一個 array of DOM nodes ```javascript var arr = document.getElementsByClassName("a-class"); var arr2 = document.getElementsByTagName("div"); ``` 3. 用 CSS 的一部份 selector 來選取 ```javascript var target = document.querySelector("#target"); var arr = document.querySelectorAll(".a-class"); ``` --- ### 瀏覽節點 * 從某個 DOM node 找到下一層的節點 (These are properties, not functions) ```javascript var arr = parentNode.children; var element1 = parentNode.firstElementChild; var element2 = parentNode.lastElementChild; var count = parentNode.childElementCount; ``` --- ### 增減節點 * 在 document 底下 或是 **某個節點前後** 增減節點 ```javascript var newElement = document.createElement(“div”); var newText = document.createTextNode(“Hello!”); ``` ```javascript // become the last child var appendedNode = parentNode.appendChild(childNode); // removed from parent var removedNode = parentNode.removeChild(childNode); // insert before refNode var insertedNode = parentNode.insertBefore(newNode, refNode); // replace child node var replacedNode = parentNode.replaceChild(newNode, oldNode); ``` --- ### 修改節點內容 * 修改節點內容、屬性、樣式... 等 #### These are properties, not functions ```javascript // get the serialized HTML code for all of its children const childrenHTMLCode = thisNode.innerHTML; // replace all of its children using the HTML code thisNode.innerHTML = childrenHTMLCode; // modify CSS style thisElement.style.color = “red”; // modify properties thisElement.className = “new-class1 new-class2”; thisElement.classList.add(className); thisElement.classList.remove(className); ``` --- ### 事件監聽綁定 (方法一) -- addEventListener() ![](https://i.imgur.com/RhHXa67.jpg) ---- ### 事件監聽綁定 (方法一) ```htmlembedded <button id="target">是個按鈕</button> ``` ```javascript var targetElement = document.getElementById("target"); targetElement.addEventListener( "click", function() { // ..做一些事,任何事,你希望按鈕按了要幹麻? alert('你希望按鈕按了要幹麻?'); } ); ``` ---- ### 事件監聽綁定 (方法二) -- GlobalEventHandlers \[[ref](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers)] * target.onclick = functionRef; ```htmlembedded <p>Click anywhere in this example.</p> <p id="log"></p> ``` ```javascript let log = document.getElementById('log'); log.onclick = inputChange; function inputChange(e) { //.. some something here } ``` ---- ### 事件監聽綁定 (方法三) -- <br>As a tag attribute * List of global attributes \[[ref](https://developer.mozilla.org/en-US/docs/Glossary/Global_attribute)] ```javascript <div class="myClass" onclick="clickHandler()"> ``` --- ## End
{"metaMigratedAt":"2023-06-14T20:19:53.032Z","metaMigratedFrom":"YAML","title":"Introduction to JavaScript (02/27)","breaks":true,"slideOptions":"{\"theme\":\"beige\",\"transition\":\"fade\",\"slidenumber\":true}","contributors":"[{\"id\":\"752a44cb-2596-4186-8de2-038ab32eec6b\",\"add\":16578,\"del\":2604},{\"id\":\"9a7bf29c-b92e-4280-bcb4-968a7895b32e\",\"add\":3,\"del\":0},{\"id\":\"a202b02b-072b-4474-be14-c5a3f8932dbb\",\"add\":5,\"del\":16}]"}
    2059 views