---
# System prepended metadata

title: JavaScript筆記
tags: [Javascript]

---

## 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字串轉成物件或值

:::