## Introduction :::info - Javascript能改變html的內容 - `getElementById()`是用來查找特定id名稱的html元素,並改變該元素內容 ```html <p id="demo">JavaScript能夠改變HTML內容</p> <button type="button" onclick='document.getElementById("demo").innerHTML = "Hello JavaScript!"'>點擊我</button> ``` 點擊前 ![image](https://hackmd.io/_uploads/ryk9YyZ3a.png) 點擊後 ![image](https://hackmd.io/_uploads/HyHhYkWnT.png) - p.s. JavaScript同時接受單引號和雙引號 - 可通過`display`樣式隱藏元素 ```html <p id="demo">JavaScript能夠隱藏HTML元素</p> <button type="button" onclick="document.getElementById('demo').style.display='none'"> 點擊我! </button> ``` 點擊前 ![image](https://hackmd.io/_uploads/B1Knc1-26.png) 點擊後 ![image](https://hackmd.io/_uploads/H1zC91-hp.png) - `display="block"`顯示隱藏的block ::: ## Javascript v.s. Typescript :::success - Typescript - Javascript的超集 → 任何有效的 JavaScript 程式碼也是 Typescript 的有效程式碼,但增加一些javascript沒有的功能 eg.Interfaces、Generics、Enums - 主要用途:允許開發者在程式碼中添加類型註解,並提供靜態類型檢查,也就是在編譯時能檢測出許多常見錯誤(變數類型錯誤、方法不存在等),從而增加程式碼的可靠性、可讀性和可維護性 - 優點:提高程式碼的可讀性、和Js相容、利於寫大型專案(因為它提供了模組化和名稱空間的支持,有助於保持代碼的結構性和可擴展性) ::: :::info - Javascript和Typescript差別 | | Javascript | Typescript | | -------- | ---------- | ---------- | | 類型系統 | Javascript 是動態型別的語言,意味著變數的類型可以在程式執行期間改變(type的檢查在執行時才做)。 | Typescript 則是靜態型別語言,變數的類型在宣告時就已確定,這有助於在程式碼執行之前找出可能的錯誤。 | | 編譯器 | Javascript無需編譯即可在瀏覽器中直接執行。 | Typescript 需要編譯才能變成 Javascript 程式碼才能在瀏覽器中執行。 | | 物件導向程式設計 | Javascript 雖然也有 class 與 object,但並無 interface,相對於 Typescript 而言物件導向程式設計的表達較不直覺。 | Typescript 支援 interface、class 和 object,可以更直觀地進行物件導向程式設計。 ::: ## 基本語法 :::success ### 在HTML中加入JavaScript - 法一: - 將JavaScript程式碼放入`<script>...</script>`標籤,鑲嵌在`<body>`或`<head>`中任意位置 - `<body>` → 頁面加載時被執行,速度增加 - `<head>` → 在被調用的时候才執行、會傳入參數的function - 法二: - javascript code寫成獨立的檔案(.js),引用外部.js檔案(可以引用多個) `<script src="URL/檔案路徑/檔案名稱"></script>` - 通常外部引用放在`<head>`最前面 ::: ## Output :::info - `innerHTML`可改變HTML內容('='後面可以接變數、數字、文字、算式…) ``` <p id="demo"></p> <script> document.getElementById("demo").innerHTML = 5 + 6; </script> ``` - `document` → 目前的HTML文檔 - `innerHTML` → 定義HTML要顯示/替換的內容 - `id` → 定義的HTML元素 - `document.write()` - 改變HTML內容(通常用於測試) - 限制:不能在頁面加載完成(所有的內容都顯示於瀏覽器上)以後使用,會覆蓋整個頁面內容 - eg: (加載完成後使用`document.write()`) ``` <p>My first paragraph.</p> <button type="button" onclick="document.write(5 + 6)">Try it</button> ``` ![Untitled (1)](https://hackmd.io/_uploads/rkkeKkW3a.png) 頁面加載完成 **↓** ![Untitled (3)](https://hackmd.io/_uploads/BJWqYJ-2a.png) 再按button會覆蓋整個頁面 (加載過程中使用`document.write()`) ```html <p>My first paragraph.</p>` <script> document.write(5 + 6); </script> ``` ![Untitled (4)](https://hackmd.io/_uploads/B1MTYkZn6.png) 3. `alert()` - 以下拉視窗顯示內容 ```html <script> alert(5+6); </script> ``` ![Untitled (5)](https://hackmd.io/_uploads/BJw1qJZhp.png) - `console.log()` - debug時在控制台顯示某個數值顯 - 括弧內可以放入一個或是多個參數或變數,可印出布林值、變數值、字串等 - 按F12可以debug→選擇”console” → 再次執行就會看到內容 ::: ## Statement :::success - javascript由多個Statement(一行指令)組成,每段程式結尾都是以分號表示,但JavaScript能夠自動幫你在未加上分號的結尾加上分號(不加容易出錯!) ### Keyword (後面會介紹) ![image](https://hackmd.io/_uploads/Byen4wDn6.png) ::: ## Syntax :::info - 可以用 "" 或 '’ - ‘+’可以連接兩個字串 eg:`"John" + " " + "Doe”` → John Doe - 大小寫不同 eg:LET != let - 命名方式 1. Hyphens連字號 eg:first-name 2. Underscore eg:first_name 3. Upper Camel Case (Pascal Case) eg:FirstName 4. Lower Camel Case eg:firstName ::: ## Comment :::success - 單行:// - 多行:/* */ ::: ## Javascript 變數 ::: info - JavaScript 變數可以透過 4 種方式宣告: - Automatically:未宣告變數型別,系統自動宣告成var - var:可用於全域、區域變數,若重複宣告會覆蓋先前的值,如果全域與區域中有同名的變數,則區域會暫時覆蓋全域 - let:用於宣告只作用於當前區塊的變數 - var定義了一個全域變數,或是在整個function而不管該區塊範圍;let變數範圍是在其定義的區塊內(只存活在{}內) - var或let變數若未賦值則被定義為undefinded,無法存取 ``` function varTest() { var x = 1; { var x = 2; // 這裡的 x 與 function 區塊內部的 x 是一樣的,因此會影響 function 區塊內所有的 x console.log(x); // 2 } console.log(x); // 2 } ``` ``` function letTest() { let x = 1; { let x = 2; // 這裡的 x 與 function 區塊內部的 x 是不同的,只會作用在這層block區塊中 console.log(x); // 2 } console.log(x); // 1 } ``` - const:用於宣告只作用於當前區塊的變數,為唯獨變數,不可修改 | | 作用範圍 | redeclare | reassign | this指向當前對象 | | ----- | -------- | ------------------- | -------- | --- | | var | 全域 | O(以第二次的值為主) | O |O | | let | 區域 | X | O | X | | const | 區域 | X | X | X | ::: ## Operation :::success ### Arithmetic Operators ![Untitled (9)](https://hackmd.io/_uploads/H1Ha3kb2p.png) - ** → 指數,Math.pow(x,y)相等於`x = x ** y`或`x **= y` ### Comparison Operators 比較運算元的型別和值 ![image](https://hackmd.io/_uploads/BkV3yuDh6.png) - == 和 !=:假如兩個運算元不具有相同型別,在比較時會嘗試轉換成相同型別 - === 和 !==:不轉換成相同型別,嚴格進行比較 - 數字+數字為數字和,字串+數字為字串 - ternary operator:`條件 ? 值1 : 值2`若條件為true則回傳值1,反之回傳值2 ### Type Operators ![image](https://hackmd.io/_uploads/S1BeM_vha.png) - typeof:回傳代表運算元類型的字串 eg.function、string、number、object ### Bitwise Operators - 運算元(十進制)被轉換為 32 bits 的整數以二進位形式表示 ,大於 32 bits 的數字將被捨棄多出來的位元 - 運算子會對於 bit 進行運算,結果也是基於 bit 來決定的 ![image](https://hackmd.io/_uploads/rkovzdwnT.png) - 移動運算子會將運算元轉換成 32 bits 的整數,並且會回傳與左方運算元相同的型態 ### ::: ## DataType :::success 8種Datatypes - String - Number - Bigint - Boolean - Undefined - Null - Symbol - Object-{name:value,name:value} - object - array - date ::: ## Function :::info - 組成:有特定功能的block of code - 語法: 1. declaration(JS會自動將宣告提升到現在scope的最頂端,所以可以在宣告前先呼叫) ``` function function_name(參數){ ... } ``` 2. expression(function內容可以存入變數) ``` const 變數 = function (參數){//return內容};//因為被視為一行執行程式所以要加分號 ``` eg: ``` const x = function (a, b) {return a * b}; let z = x(4, 3);//x變成function代稱可以用來呼叫function ``` 3. function() constructor ``` const 變數 = new Function(參數和return算式); ``` 4. arrow function ``` const 變數 = (參數) => {要return 的值} ``` - 沒有this → 不能用在object method - 不能被自動提升成全域 → 要在使用前宣告 - 通常用const因為回傳值是常數 - Parameter → 列在括號內的變數名 argument → 呼叫時傳入的值 回傳型態為function → 因為JavaScript為動態型別 - Argument:pass by value Object:pass by reference - 呼叫: 1. Function名:取得funtion的內容 2. Function名():計算function取得結果 3. function constructor:用new呼叫function(建立一個物件,因為function算是一個物件) eg: ``` // This is a function constructor: function myFunction(arg1, arg2) { this.firstName = arg1; this.lastName = arg2; } // This creates a new object const myObj = new myFunction("John", "Doe"); // This will return "John" myObj.firstName; ``` ::: ## Object :::success - 變數的一種,可以包含許多值,一對值寫為`name : value` eg.`const objectName = {name1:value1, name2:value2, name3:value3};` ### Object Properties - 屬性是與object關聯的值,object是無序屬性的集合,通常可以更改、新增和刪除 - 存取屬性 1. objectName.propertyName 2. objectName[“propertyName”] - 新增屬性 - existObject.newPropertie = "newValue"; - 刪除屬性(包含值) - delete existObject.existPropertie ### Object method - this - https://blog.techbridge.cc/2019/02/23/javascript-this/ - 代表一個object,不是代表一個變數,所以不能改變this的值 - 代表哪個object取決於如何被呼叫 ![Untitled (11)](https://hackmd.io/_uploads/rJalelW26.png) - 無論嚴格或非嚴格模式下,this在函數外皆代表全域變數;在函數內則取決於該函是如何被呼叫 - 嚴格模式下,this值預設為undefined - 可以用call、apply、bind改變this的值 - call():用傳入的參數覆蓋this的值 - apply():和call相同,差別為傳入的參數須為array - bind():會回傳一個新function,將該function綁定傳入的參數值 - Accessing Object Methods - 語法:`objectName.methodName()` - 當使用()呼叫時,屬性將作為函數執行;若不加(),則會回傳該函數定義 - 向物件新增method: ``` object.name = function () { ... return ... }; ``` - 內建method:toUpperCase()、length等 - object沒有index所以只能用for in或forEach()存取 (詳見for loop) - object轉array `Object.values(要轉換的object)`:回傳轉換後的array ### Map(這個MAP不是function) - 組成:key-value(key可以是任何型態) - 依照元素插入的順序排序 #### method - 創建map: 法一:`new Map(由key和value組成的array)` eg: ``` const fruits = new Map([ ["apples", 500], ["bananas", 300], ["oranges", 200] ]); ``` 法二:`new Map`並用`Map.set(key, value)`新增元素 eg: ``` const fruits = new Map(); // Set Map Values fruits.set("apples", 500); fruits.set("bananas", 300); fruits.set("oranges", 200); ``` - 修改/增加元素:`map_name.set(key,value)` - 取出map中key對應的值:`map_name.get(key)` - map大小:`map_name.size` - 刪除map中元素:`map_name.delete(key)` - 查詢元素(true/false):`map_name.has(key)` - 把map每對元素呼叫執行function:`map_name.forEach(function(value,key){//function內容})` #### object和map差別 ![image](https://hackmd.io/_uploads/ByYbtwd3p.png) ::: ## Event :::success - 在網頁中發生的各種交互作用或狀態改變,eg:滑鼠游標碰到、頁面大小改變… → Javascript可以回應這些互動 - 語法: ``` <element event='some JavaScript'> ``` 通常要執行的Javascript都是由多行組成,所以通常用呼叫function的方式 eg: 法一: ``` <button onclick="document.getElementById('demo').innerHTML = Date()">The time is?</button> <p id="demo"></p> ``` 法二: ``` <button onclick="this.innerHTML=Date()">The time is?</button> ``` (this代表當前被點擊的按鈕元素) **↓** ![Untitled (13)](https://hackmd.io/_uploads/rJXige-n6.png) 按button會出現現在時間 - 其他Event ![Untitled (12)](https://hackmd.io/_uploads/HJ0YlgZ2T.png) ::: ## Strings :::info JavaScript String用於存儲和操作文本 ```html let text = "John Doe"; ``` ### Template String - use back-ticks (``) rather than the quotes ("") to define a string ``` let text = `Hello World!`; ``` - `${...}`提供一種將變數和表達式插入字串的方法 ```htmlembedded <p id="demo"></p> <script> let firstName = "John"; let lastName = "Doe"; let text = `Welcome ${firstName}, ${lastName}!`; document.getElementById("demo").innerHTML = text; </script> ``` ![image](https://hackmd.io/_uploads/HJE3UxZn6.png) - 允許字串中有表達式 ``` <p id="demo"></p> <script> let price = 10; let VAT = 0.25; let total = `Total: ${(price * (1 + VAT)).toFixed(2)}`; document.getElementById("demo").innerHTML = total; </script> ``` ![image](https://hackmd.io/_uploads/HJfRIeb2T.png) - Method - Length ``` 變數.length; ``` - Extract Character(read only,不能改內容) eg. 1. `at(*position*)` -可以有負的index 2. `charAt(*position*)` -若找不到回傳空字 - Extracting String Parts eg. `substring(*start*, *end*)`:取子字串 - Upper/Lower Case - `toUpperCase()` - `toLowerCase()` - 連接兩個或多個string - `concat()` - 去掉頭尾的空格 - `trim()` -去掉頭尾的空白 - `trimStart()` -去掉頭的空白 - `trimEnd()` -去掉尾的空白 - Padding-補齊/去除到特定長度 - `padStart()`:從前開始補 - `padEnd()`:從後開始補 - 取代字串 - `replace(要被取代的字串,要取代成什麼)` -指取代第一次遇到的字串、大小寫不同 - 常用正則表達式: `/字串/g`:取代每個字串 `/字串/i` :不分大小寫取代 - `replaceAll(要被取代的字串,要取代成什麼)`-取代每個字串、大小寫不同 要被取代的字串要是”字串”或是/字串/g - String轉array - `split()`:切割字串再存為陣列 eg: `split(“,”)`以逗號分割將每個字放人分別的index中 `split()`將整個字串放入index[0] `split(“”)`將每個字母切割 - 找出相同的字存到陣列 eg. - `match()` -可以用”字元”或是/字元/,只會匹配第一個遇到的字 - `matchAll()` -字串要是”字串”或是/字串/g,匹配遇到的所有相同字串 ::: ## Number :::info - NaN = Not a Number - `isNaN()` -判斷是否是數字 - `typeof NaN` returns number - `Infinity`-超出數字最大範圍時回傳Infinity - `typeof Infinity` returns number - BigInt - 超出Safe-Number(from -(253 - 1) to +(253 - 1))範圍的數字,並以字串儲存,不能有小數點 - 宣告:`BigInt(數字)` 、`數字n` - Min/Max Safe Integers - `MAX_SAFE_INTEGER` - `MIN_SAFE_INTEGER` - 判斷是否是int(true/false) - `Number.isInteger()` - 判斷是否是在安全範圍內的int(true/false) - `Number.isSafeInteger()` - Method ![Untitled (14)](https://hackmd.io/_uploads/BkKw4eZ26.png) ![Untitled (15)](https://hackmd.io/_uploads/rkquVlZna.png) - `toExponential(要到小數點第幾位)` -將數字轉成科學符號,並回傳String - `toFixed(要到小數點第幾位)` -將數字四捨五入到小數點後第幾位 - `toPrecision(總共要幾位)` -總共要幾位數字,並回傳String - `valueOf()` -將不是數字型態的數轉成數字型態 - `Number()` -將不是數字型態的數轉成數字型態 - Property ![Untitled (17)](https://hackmd.io/_uploads/rJc9Ng-3T.png) - `EPSILON`-因為浮點數是取近似值,所以不能直接比較是否相等,要用EPSILON來判斷兩個浮點數的相差值是否小於(大於1的最小浮點數-1),以判斷浮點數的值是否相等 - MAX_VALUE -Javascript可以表示的最大數字,接近無限大,但在數字很大時精確度低 MAX_SAFE_INTEGER -可以被精確表示的最大整數 ::: ## Array ### 宣告: :::info - 法一:`const array_name = [item1, item2, ...];` - 法二:`const array_name = [];//之後再給予element值` *同一個 array中可以存不同型態的 item: object、function、array...* ::: ### array的存取 :::info - 存取整個array: 直接打array_name: `document.getElementById("demo").innerHTML = (array_name); //此時"demo"的內容會變成array裡所有物件` - 一個個取出所有元素: - 法一:迴圈 ``` for (let i = 0; i < n; i++) { //程式碼 } //做到第n個,全部做完n=array.length-1 ``` - 法二:`array_name.forEach() //把每個都做一次` - 存取各個item內容: 用index取值: `array_name[(index)]` ::: ### array iteration :::info - `forEach()`:把array中元素取出來傳入callback function(參數有value,index,array順序固定但index、array不一定要有值)中,不會修改原陣列值,且沒有return - `map()`:建立一個新陣列,其內容為原陣列中每個元素計算以後回傳結果(所以一定要有return)形成的集合(和forEach()類似差在map()會把結果存到新的陣列中) - `flatMap()`:先執行完map()再做flat(預設為一級展開,就是把一個陣列中第二層的括號拿掉 eg:[1, 2, [3, 4, [5, 6]]]→[1, 2, 3, 4, [5, 6]]) - `filter()`:建立一個新陣列,且存入的內容會經過篩選(eg:大於某數) - `reduce()`:將陣列中每個元素(由左至右)和回傳值再次做運算(累加、比較...),function有目前總和、value、index、array - `reduceRight()`:在由右至左做reduce() - `every()`(true/false):確認陣列裡面每個元素是否都通過篩選 ::: ## Array/object的差別 :::info * Array和object差別 || index | 宣告 | | -------- | -------- | --------------------------------------------------------------------------- | | array | Text數字 | `array_name = [items];` 若[ ]中只有一個數字代表宣告幾個undefined type的元素 | | object |名稱(String)| `array_name = new Array(items)`只有一個item要用var宣告 | ::: ### function :::info * array轉string:`array_name.toString()` * 元素數:`array_name.length` * 排序元素:`array_name.sort()` * 增加元素(加到最後): 法一:`push(item)` 法二:`array_name[array_name.length]` * 判斷是否為array: 法一:`typeof array_name` 法二:`array_name.isArray();` 法三:`array_name instanceof Array;` ::: ## For Loop ### for in :::info - 用途:存取object/array中property的**key**(但array中不一定會照順序存取) - 語法: ``` for (key in object/variable in array) { // code block to be executed } ``` eg ``` const person = {fname:"John", lname:"Doe", age:25}; let txt = ""; for (let x in person) { txt += person[x] + " "; //因為是存取key所以要用person[x]才能取得值 } ``` ::: ### for of :::info - 用途:存取可以迭代的object(eg: Arrays, Strings, Maps, NodeLists)的**值** - 語法: ``` for (variable of iterable) { // code block to be executed } ``` ::: ### map :::success map() 方法會**建立一個新的陣列**,把原陣列的每一個元素經由function運算後所回傳的結果塞到新陣列。 ``` const array1 = [45, 4, 9, 16, 25]; const array2 = array1.map("這邊放function"); //假設function是把數字*2,array2的內容就會是[90,8,18,32,50] ``` - 方法: 1. `const array2 = array1.map((x) => x * 2);` 2. `const array2 = array1.map(myFunction); function myFunction(value, index, array) { return value * 2; }` 3. `var array2 = array1.map(function (x) { return x * 2; });` //`map()`每次用時都會出現新陣列,因此如果不需要新陣列出現的話用`forEach()`之類的就好 ::: ### 正則表達式 :::info * 功能:比對字串 * 語法:/`正則式`/ * 符號 \ → 跳脫符號 . → 任意字元 $ → 以...結尾 ^ → 以...開頭(在[]中代表否定 = []內的字都不要) [] → 可以使用得範圍 * 匹配次數 \* → 任意次數,等同於 {0,} \+ → 至少一次,等同於 {1,} ? → 零或一次(有或沒有),等同於 {0,1} ?: → 某一區塊重複出現 {m} → m 次 {m, n} → 從 m 到 n 次 * EG 電話號碼:/^09[0-9]{2}-[0-9]{6}/ → 以09為開頭接兩個0-9數字後加上"-"再接6個0-9數字 email:/\^[a-zA-Z0-9]+@[a-zA-Z]+(?:\\.[a-zA-Z]+)+$/ → 以一個以上英文或數字為開頭@一個以上英文字母一組以上的".加多個英文字母"為結尾 ::: ### localStorage :::success 將資料從頁面中的程式碼儲存到Web瀏覽器的儲存空間當中,本來存入程式碼當中的資料,就不會因重新整理頁面或者關閉瀏覽器而消失,可以跨瀏覽器分頁使用且資料無期效限制,將永久被保留 - 存值到localStorage `localStorage.setItem(key, value)`: 指定物件屬性的 key 以及 value,可以在 storage 物件中加入屬性或修改原本的屬性內容 - 從localStorage取值 `localStorage.getItem(key)`: 輸入屬性的 key,可以得到 storage 物件對應屬性的 value - 移除資料 - `localStorage.removeItem(key)`: 把指定的屬性從 storage 物件中移除 - `localStorage.clear()`: 清除所有的資料 #### 資料只能為字串!! localStorage的key和value只接受字串 - 轉成JSON格式的字串 `JSON.stringify(value)` - 接收字串轉回原本的值 ` JSON.parse() `:接收JSON字串轉成物件或值 :::