---
# System prepended metadata

title: 每日任務重點筆記

---

# 每日任務重點筆記

>[TOC]

<style>
.blue {
  color: blue;
}
</style>
### 變數宣告（let、const）

**知識點：使用 let、const 宣告變數**
* const： 一般使用在變數不會被重新指定值
* let：一般使用在變數可能會被重新指定值

---

### 型別判斷（數字、字串、NAN...）

**知識點：型別判斷**
* 數字 ＋ 字串 ＝ 字串
* 數字字串 ＊ 數字字串 ＝ 數字
* 數字 - 數字字串 ＝ 數字
* 數字 - 中文字串 ＝ NAN
* 數字 * 中文字串 ＝ NAN

```
let a = 1 +"2"+ 3 ;
let b = "1" * "1";
let c = 2 - "1";
let d = "我好棒" - 1;
let e = 1 * "我好棒";
// 印出 "123" 1 1 NaN NaN 
```

---

### 字串處理實用方法及如何轉型（parseInt()、toString()）

**知識點：字串處理**
* 過濾空白方法：字串.trim()
* 字串轉型為數字：parseInt(字串)
* 數字轉型為字串：數字.toString()

```
let myEmail = "  123456@gmail.com";
let myPassword = "    987654321";
myEmail = myEmail.trim();
myPassword = myPassword.trim();

let a = "1";
let b = "2";
a = parseInt(a);
b = parseInt(b);

let countryCode = 886;
let myNumber = 123456789;
countryCode = countryCode.toString();
myNumber = myNumber.toString();
```

---

### 邏輯運算子
**知識點：**
* 比較與邏輯運算子
* 流程判斷 - if、else if、else
* 使用語法：|| &&

___

### 陣列宣告、取值、新增
**知識點：**
* 陣列的基礎寫法：
外層使用[ ]包覆，內層元素間用逗號區隔，在讀取陣列時會由零開始
    ```
    let array = [0,1,2];
    console.log(array[0])//陣列的讀取方法，從零開始
    console.log(array.length)//讀取陣列長度
    ```
* 陣列的新增方法：
    ```
    let array = ['item1'];
    console.log(array);//["item1"]

    //陣列預設寫入資料
    array[1] = 'item2';
    console.log(array);//["item1","item2"]

    //push 寫入資料
    array.push('item3');
    console.log(array);//["item1","item2","item3"]

    //unshift 寫入資料
    array.unshift('item0');//["item0", "item1", "item2", "item3"]
    console.log(array);
    ```

---

### 物件宣告、取值、新增

**知識點：**

**以下兩個方法可以讀取物件：**
1. 使用`.`點記法

    ```javascript=
    let obj = {
        myName:'王小花',   
    };

    //讀取物件屬性
    console.log(obj.myName)//王小花

    //新增物件屬性
    obj.key = 'value';
    console.log(obj)//{myName: "王小花", key: "value"}
    ```
2. 使用`[]`括弧記法
通常情況下會使用`.`取值，但某些情況無法用`.`取值，例如屬性為數字開頭時，或要讀取變數的情況下皆會使用`[]`。

    ```javascript=
    let obj = {
        myName:'王小花',   
    };
    //讀取物件屬性
    console.log(obj['myName']);//王小花

    //新增物件屬性
    obj['key'] = 'value';
    console.log(obj);//{myName: "王小花", key: "value"}

    //讀取變數的情況
    let a = 'myName';
    console.log(obj[a])//王小花
    ```

---
### 函式、return

**知識點：**

**以 return 寫法：**
``` javascript
function calcTotalScore(chineseScore,mathScore){
return chineseScore + mathScore; //回傳，會把值回傳到呼叫 calcTotalScore 的地方
}

// return 回傳後的值，可以被賦予在變數上
//我宣告一個變數，名為 markTotalScore，並賦予右邊函式的值。
let markTotalScore = calcTotalScore(40,60);//會先將參數丟進 calcTotalScore 運算後，接收 return 回傳的值
console.log(markTotalScore)//100
```

---

### DOM 選取網頁元素

**知識點：**

1. **querySelector、textContent、 innerHTML**
2. **textContent、innerHTML 差異**

* 選取 HTML 元素
* 選取 class、id
* 透過後代選擇器方式，選取節點
```htmlembedded=
<ul class="list">
<li></li>
</ul>
```
```javascript=
const listContent = document.querySelector('.list li');
```
當我們透過 querySelector 選擇到節點後，就能使用 textContent 來動態修改裡面的 Text 文字內容
```htmlembedded=
<h1></h1>
```
```javascript=
//使用 querySelector 選取到 h1 Element
const el = document.querySelector('h1');

// 針對該 h1 元素 Element 去賦予文字內容
el.textContent = "Hello World";
```
當我們透過 querySelector 選擇到節點後，就能使用 innerHTML 來增加 HTML 網頁結構，innerHTML 會將選取到的結構內原有內容刪除，並重新寫入新增的內容，以下將示範如何修改
```htmlembedded=
<div class="header"></div>
```
```javascript=
//使用 querySelector 選取到 class 
const header = document.querySelector('.header');

//針對該 class 內去增加 HTML 網頁結構，結構內容為自行組出的字串資料(建議使用反引號``包覆)
header.innerHTML = `<h1 class="title">標題1</h1>`;
```

---

### setAttribute、getAttribute 實作

**知識點：**
**setAttribute、getAttribute**

我們可以透過 setAttribute 來設定指定元素上的屬性
```htmlembedded=
<a href="#"></a>
```
```javascript=
//先透過 querySelector 選取 a Element
const myLink = document.querySelector('a');

//設定該 Element 的 href 屬性
myLink.setAttribute("href","https://www.hexschool.com");

//設定該 Element 的 class 屬性
myLink.setAttribute("class","red");
```
我們可以透過 getAttribute 來取出指定元素上的屬性
```htmlembedded=
<a href="https://www.hexschool.com" class="red"></a>
```
```javascript=
//先透過 querySelector 選取 a Element
const myLink = document.querySelector('a');

//取出該 Element 的 href 屬性
console.log(myLink.getAttribute("href"));//"https://www.hexschool.com"

//取出該 Element 的 class 屬性
console.log(myLink.getAttribute("class"));//"red"
```
---

### 表單欄位取值

**知識點：**
**.value 取值**
**addeventListener**

我們可以透過 .value 來取出表單元素 Elements ，但要注意<span class="blue">取出的值都會是"字串"</span>。
input 欄位取值示範：
```htmlembedded=
<input type="text" class="txt" value="你好棒！">
```
```javascript=
//先透過 querySelector 選取 class txt
const txt = document.querySelector(".txt");
console.log(txt.value)//你好棒！
```

select 取值示範：
```htmlembedded=
<select class="list">
  <option value="蘋果">蘋果</option>
  <option value="水蜜桃">水蜜桃</option>
  <option value="西瓜">西瓜</option>
</select>
```
```javascript=
//先透過 querySelector 選取 class list
const list = document.querySelector('.list');
console.log(list.value)//蘋果
list.value = "水蜜桃";
```
可透過 addeventListener 監聽網頁 Event 事件
```htmlembedded=
<input type="button" class="btn" value="點擊">
<h1></h1>
```
```javascript=
//先透過 querySelector 選取 class btn
const btn = document.querySelector('.btn');

//先透過 querySelector 選取 h1 Element
const title = document.querySelector('h1');

//監聽 click 事件，點擊了按鈕，就會觸發函式的內容
btn.addEventListener("click",function(e){
    title.textContent = "你被點擊了！！";
})
```
---

### e.target 搭配 nodeName 節點

**知識點：**
**event**
**e.target、nodeName**

我們可以透過 event 來得知目前 DOM 所發生的事件，如點擊按鈕、按鍵盤等，可以與 addEventListener() 搭配使用，以下為示範：

監聽使用者 click 點擊事件
```htmlembedded=
<button type="button">送出</button>
```
```javascript=
//先透過 querySelector 選取 button
const button = document.querySelector("button");

//監聽使用者點擊就會執行大括號的內容
button.addEventListener('click',function(e){
  console.log('123')//點擊按鈕就會印出 123
})
```
監聽使用者 keydown 鍵盤事件
```htmlembedded=
<input type="text">
```
```javascript=
//先透過 querySelector 選取 input
const input = document.querySelector("input");

//監聽使用者按鍵盤就會執行大括號的內容
input.addEventListener('keydown',function(e){
  console.log(e.key)
})
```
e.target 會指向目前選取到的 DOM 物件，可以搭配 nodeName 去得知目前點選的節點名稱，以下為示範：
情境：判斷是否點擊到按鈕
```htmlembedded=
<ul class="list">
  <li>內文</li>
  <li>內文<button type="button">按鈕</button></li>
  <li>內文</li>
</ul>
```
```javascript=
//先透過 querySelector 選取 class list
const list = document.querySelector(".list");

//監聽使用者點擊就會執行大括號的內容
list.addEventListener("click", function (e) {

//監聽使用者點擊到的是否為 <button></button> 按鈕
  if (e.target.nodeName === "BUTTON") {
    console.log("123"); 
  }
});
```

---
### 取消表單預設效果

**知識點：**
**preventDefault**
**表單預設行為**
取消 HTML 標籤的預設行為，以下為示範：
```htmlembedded=
<a class="myLink" href="https://www.hexschool.com/">連結</a>
```
```javascript=
//先透過 querySelector 選取 class myLink
const myLink = document.querySelector(".myLink");

//監聽使用者點擊就會執行大括號的內容
myLink.addEventListener('click',function(e){
  e.preventDefault();//阻止 a 標籤默認行為，所以不會轉址
  console.log("有被點擊到");
})
```
表單預設行為
如果使用 <input type="submit"> submit ，或是使用 <button></button> 但不指定 type 屬性時預設也會是 submit，而 submit 會將表單提交到伺服器。
我們通常不會使用這個方式提交表單給伺服器，所以會使用 preventDefault 取消它的預設行為，範例如下
```htmlembedded=
<form action="#">
    帳號:
    <input type="text" name="email"> 
    <br>
    密碼:
    <input type="text" name="passward"> 
    <input type="submit" value="送出">
</form>
```
```javascript=
//先透過 querySelector 選取 form
const form = document.querySelector("form");

//監聽使用者點擊就會執行大括號的內容
form.addEventListener("click", function (e) {
  e.preventDefault();//阻止 submit 屬性默認行為，所以不會提交資料
});

```


---
### 陣列 forEach 寫法

**知識點：**
**forEach() 是陣列的方法**
**forEach 寫法介紹**
**搭配 if，篩選出陣列裡面有幾個偶數**
**forEach 讀取資料**

forEach() 是陣列的方法，會將陣列內的每個值都遍歷。
可以帶入三個參數(參數名稱可自定義)：

1. item 當下陣列的值
2. index 迭代資料的索引值
3. array 執行的陣列本身

forEach 寫法介紹
```javascript=
let data = [30,40,50];
data.forEach(function(item,index,array){
  console.log(item,index,array);
})
```


forEach() 內可以搭配 if ，並透過在全域宣告變數 total ，累加計算陣列內偶數數字數目
```javascript=
let data = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let total = 0;
data.forEach(function (item, index, array) {
  if (item % 2 == 0) {
    console.log(item)//2,4,6,8
    total += 1;
  }
});
console.log(total);//4
```
如果陣列內有多筆物件，可以透過以下方法取出物件內的值
```javascript=
let hexSchoolDiscord = [
  {
    channelName: "六角筆記王",
    teacher: "廖洧杰",
    teachingAssistant: "Vivian"
  },
  {
    channelName: "js-必修篇",
    teacher: "廖洧杰",
    teachingAssistant: "艾草"
  }
];
hexSchoolDiscord.forEach(function (item) {
  console.log(item.channelName); 
  console.log(item.teachingAssistant);
});
```
---
### 如何整合 innerHTML 資料

**知識點：**
**整合 innerHTML 資料**
**重要觀念釐清**


可以透過 forEach 與 innerHTML 整合，一次渲染多筆資料在網頁上，以下為示範：
```htmlembedded=
<ul class="list"></ul>
```
```javascript=
let data = [
  {
    name: "艾草",
    stir: true
  },
  {
    name: "Vivian",
    stir: false
  },
  {
    name: "鵬聖",
    stir: true
  },
  {
    name: "雅萱",
    stir: true
  }
];
//透過 querySelector 選取 class list
const list = document.querySelector(".list");
//透過在全域宣告 str 累加內文
let str = "";
data.forEach(function (item) {
  //判斷是否會攪拌
  if (item.stir) {
    str += `<li>會攪拌咖哩飯的人有${item.name}</li>`;
  } else {
    str += `<li>不會攪拌咖哩飯的人有${item.name}</li>`;
  }
});
//將結果透過 innerHTML 的方式渲染在網頁上
list.innerHTML = str;
```

**重要觀念釐清**
放至 forEach 內時 innerHTML ，其實是不斷的被執行的，而放置於迴圈外 innerHTML 僅會執行一次，可以更節省效能。

---
### 網頁請求狀態碼

**知識點：**
**AJAX - 網路請求**
**網頁請求狀態碼**

**查看網頁請求狀態碼**
可按照底下步驟於 Google Chrome 網路瀏覽器上查看網頁請求狀態碼：
1. 右鍵點擊後選取檢查
2. 選取 Network

![](https://i.imgur.com/bUANBRN.png)

**網頁請求狀態碼**

我們可以從網頁請求 HTTP 狀態碼看出是否有成功發送請求，以下列出幾種常見的 HTTP 狀態碼訊息：

*  **成功回應：200~209**

    +    200 OK：請求成功。

*  **重定向：300~399**
    +    304 Not Modified ：已經有載入過，不會在跟伺服器要資料，會使用暫存的檔案。（資源與之前相較未修改，無須重新傳輸）
    
*  **用戶端錯誤 ：400~499**
    +    404 Not Found ：伺服器找不到請求的資源(找不到檔案)。
    
*  **伺服器端錯誤 ：500~599**
    +    500 Internal Server Error ：伺服器端發生未知或無法處理的錯誤(接後端資訊時，可能會遇到)。

相關網路請求代碼：
* **101 Switching Protocols**
   + 已經了解user的請求，並通過Upgrade訊息頭通知使用者採用相應的協定來完成請求。


同學也可以參考此篇 MDN 文章：[HTTP 狀態碼](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status)了解其它的狀態碼。

---
### axios-get

**知識點：**

**axios 環境安裝**
**axios-嘗試串接外部資料**

透過 axios 套件連結 CDN 的方式，載入套件，並將程式碼放置於個人 JavaScript 檔案上方：

CDN 連結：
```jsx=   
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
```
連結放置處：
```HTML=   
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

    <!-- 將 axios 套件 CDN 放置於個人 JavaScript 檔案上方 -->
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">
  </script>
  <script src="all.js"></script>
</body>
</html>
```
**axios-嘗試串接外部資料**

`axios.get` 範例程式碼：
```jsx=   
axios.get('放入想撈取的 JSON 連結')
  .then(function (response) {
    //回傳的結果
    console.log(response);
    //抓回來的 JSON 資料
    console.log(response.data);
    //回傳的狀態碼
    console.log(response.status);
  });
```


---
### 函式處理 axios-非同步

**知識點：**
**axios-非同步觀念**
**透過函式設計處理非同步**


**axios-非同步觀念**
執行 AJAX 發送網路請求後，須等待對方回傳資料，在對方尚未回傳資料時，會繼續往下執行程式碼，等對方回傳後再回去執行 .then 函式大括號的內容。


```jsx=   
let ary = [];
//發送請求
axios.get('https://hexschool.github.io/ajaxHomework/data.json')
  .then(function (response) {
  //等待對方回傳資料後執行
    ary = response.data;
    console.log(ary)//印出 response.data 回傳結果
  });
  //先執行，所以會印出空陣列
  console.log(ary)//[]
```
**透過函式設計處理非同步**

**函式處理非同步好處：** 可以確保資料有回傳後才執行函式。
```jsx=   
let ary = [];
axios.get('https://hexschool.github.io/ajaxHomework/data.json')
  .then(function (response) {
    ary = response.data;
    console.log(ary)//印出 response.data 回傳結果
    //資料回傳後，才去呼叫函式
    renderData();
  });
function renderData() {
  console.log(ary); //印出 response.data 回傳結果
}
console.log(ary);//[]
```


---
### 四種常見的 POST 請求 content-type 介紹

**知識點：**
**四種常見的 POST 請求 content-type**
1. **application/x-www-form-urlencoded**
2. **application/json**
3. **multipart/form-data**
4. **text/plain**

想傳送資料給對方伺服器時，可以透過 POST 方法發送網路請求，發送時也需要讓對方知道我們傳過去的檔案格式會是什麼。
所以我們會透過 headers 中的 Content-Type 告知對方我們要傳送的格式。

* **application/x-www-form-urlencoded**

這種方法是屬於 <form> 表單的原生提交方式：
<form> 標籤的屬性會包含 method 、method 可以使用 get 、 post 發送請求，當指定 post 請求後， <form> 標籤的 enctype 的屬性值會默認使用此方式提交：

```htmlembedded=
<form action="/action_page_binary.asp" method="post" >
  <label for="fname">First name:</label>
  <input type="text" id="fname" name="fname"><br><br>
  <label for="lname">Last name:</label>
  <input type="text" id="lname" name="lname"><br><br>
  <input type="submit" value="Submit">
</form>
```

以上範例程式碼取自 w3c ，如果想更了解 enctype 屬性，請點選 [enctype Attribute](https://www.w3schools.com/tags/att_form_enctype.asp)。

* **application/json**

目前使用到的 API 都是使用這種 Content-Type ，基本上就是透過 JSON 格式來傳遞參數資料。
透過 axios 套件發送網路請求時，默認的 Content-Type 也是此種類型。

* **multipart/form-data**
如果我們想要上傳 「檔案、圖片、影片」 等，就必須使用這種 Content-Type。
當我們使用表單標籤時，可以透過指定 enctype 屬性為 multipart/form-data 的方式來操作。

```htmlembedded=
<form action="/action_page_binary.asp" method="post" enctype="multipart/form-data">
  <label for="fname">First name:</label>
  <input type="text" id="fname" name="fname"><br><br>
  <label for="lname">Last name:</label>
  <input type="text" id="lname" name="lname"><br><br>
  <input type="submit" value="Submit">
</form>
```

此為比較進階的 post 用法，如果想更了解 form-data ，請點選此篇 [文章](https://blog.kalan.dev/2021-03-13-html-form-data/)。

關於 form 表單的 post 方法想玩玩看嗎？請點選此 👉  [連結](https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_form_enctype) 也可以移除 enctype 屬性來觀察默認的 Content-Type ： x-www-form-urlencoded 編碼方式。

* **text/plain**

基本上就是純文本格式。

---
### data- 屬性妙用

**知識點：**
**data- 屬性妙用**
**補充另一個取值的方式： dataset**

`data-"自定義名稱"`，可以拿來埋各種資料：
HTML：
```html=
<input type="text" class="txt" placeholder="請輸入待辦事項">
<input type="button" class="save" value="儲存待辦">
<ul class="list">
  <li>123
    <input class="delete" type="button" data-num="1" value="刪除待辦">
  </li>
</ul>
```
接下來可以透過 getAttribute 取值：
JavaScript：
```jsx=
const list = document.querySelector(".list");
list.addEventListener("click", function (e) {
  if (e.target.getAttribute("class") !== "delete") {
    return;
  }
  let num = e.target.getAttribute("data-num");
  console.log(num);
});
```

補充另一個取值的方式： **dataset**
```jsx=
const list = document.querySelector(".list");
list.addEventListener("click", function (e) {
  if (e.target.getAttribute("class") !== "delete") {
    return;
  }
  let num = e.target.dataset.num;
  console.log(num);
});

```
此種方法也能順利取值 dataset . 的後方請帶入 `data-"自定義名稱"` 的自定義名稱，因為這邊 HTML 自定義名稱為 num ，所以是使用 `dataset.num` 的方式。
需注意的是 假設你的 data 名稱為 `data-xxx-xxx` 在使用 dataset 獲取時需改成小駝峰寫法，舉例如下：
```htmlmixed=
<div data-todo-item="123">
123
</div>
```
```jsx=
<script>
const item = document.querySelector('div').dataset.todoItem;
console.log(item)
</script>
```

---

### 陣列 map 搭配箭頭函式寫法
**知識點：**

課程中使用陣列方法 map 的箭頭函式寫法，這邊以 todolist 較常用到的組字串 forEach 舉例：

**原本的寫法：**
```jsx=
data = [10, 20, 30];
total = 0;

data.forEach(function (item) {
  total += item;
});
console.log(total);//60
```
**箭頭函式的寫法：**
function 拿掉，並在參數後補上 => 符號，就完成囉。

```jsx=
data = [10, 20, 30];
total = 0;

data.forEach((item)=> {
  total += item;
});
console.log(total);//60
```
雖然一個參數的情況下可以不用在參數外加 () 小括號，但兩個參數以上就會報錯，所以還是建議不管有幾個參數都習慣性加上小括號唷！

**箭頭函式再精簡：**
把 {} 大括號拿掉後，縮成一行也是可以辦到的唷！
此種更精簡寫法適用於函式內程式碼不多時，程式碼較多的情況不建議使用。
```jsx=
data = [10, 20, 30];
total = 0;

data.forEach((item)=> total += item );
console.log(total);//60
```

todolist 內會使用到 forEach 整合 innerHTML 去組字串並渲染到網頁上，不熟悉的同學歡迎複習：[ 8/24 (二) － 如何整合 innerHTML 資料](https://hackmd.io/AiqAH3ztSrq58GfGbJ7Tog)。



---

### Date 物件

**知識點：**
> **Date 物件**

補充一個在埋 id 時，很常使用的方法：
Date 物件是基於世界標準時間（UTC） 1970 年 1 月 1 日開始的毫秒數值來儲存時間。

所以可以透過 `new Date().getTime()` 的方式來當成 id 使用。

```jsx=
//建立 Date() 物件後使用 getTime() 取得時間 
//getTime() 會取出 (由 1970年1月1日零時零分計起到目前時間)
let id = new Date().getTime();
console.log(id)//1629966889412 (每毫秒都不同，所以歡迎自行貼到 CodePen 觀看)
```
想更了解 Date 物件，歡迎參考此篇[文章](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Date)。


---

### findIndex

**知識點：**
> **findIndex**

透過陣列方法 findIndex 可以獲取符合條件的索引值，如果找不到符合條件的索引值，就會回傳 -1
透過此方式，搭配 splice 方法，就可以刪除特定資料，參考程式碼如下

假設下方是陣列的資料內容：

```javascript=
const orders = [
  {
    name: "艾草",
    id: 123456789
  },
  {
    name: "ViVian",
    id: 987654321
  }
];
```

使用時需要留意型別，如果型別錯誤將找不到該筆資料
(HTML 內取出的皆為字串型別)
```javascript=
// 透過 findIndex 找出符合『 id 為 123456789 』條件的索引值
let index = orders.findIndex((item) => item.id === 123456789 );
console.log(index) // 輸出結果為 0
```

以下是錯誤的寫法：
>假設真的遇到需處理字串的型別 
>建議使用雙等於 或是將資料轉換成數字後再做比較
```jsx=
let indexError = orders.findIndex((item) => item.id === "123456789" );
console.log(indexError)// -1 找不到 因為兩者型別不同
```

最終配合使用 splice 方法，透過回傳的索引值去刪除該筆資料即可。
```jsx=
orders.splice(index, 1);
console.log(orders)
```


---
### getElementById 節點

**知識點：**
> **getElementById**
> **classList**
> **closest**

**getElementById**

當要獲取綁定 Id 的元素時，也可以透過 getElementById 來獲取，getElementById 的使用方式如下：
HTML：
```htmlembedded=
<button id="addTodo" type="button">新增</button>
```
```javascript=
// 透過 getElementById 獲取 id 為 addTodo 的元素
const addTodo = document.getElementById('addTodo');
```
如果要選取其他的元素，也可以透過 querySelector 來實現，想更了解 getElementById 的使用方式，歡迎參考此篇[文章](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/getElementById)。

**classList**

classList 可以拿來確認是否包含某個特定 class 類別，與透過 getAttribute("class") 的方式要符合全部 class 類別不同，
我們可以使用 Element.classList.contains('className')，來確認該 Element 是否存在某 className 類別。
完整範例如下： 
HTML：
```html=
<button type="button" class="btn btn-outline-primary">按鈕</button>
```
JavaScript：
```jsx=
//透過 querySelector 選取 class btn 這個元素
const btn = document.querySelector('.btn');

//給該按鈕註冊點擊事件
btn.addEventListener('click',(e)=>{
    
  //方法一：透過 getAttribute("class")
  if (e.target.getAttribute("class") === "btn") {
    console.log("getAttribute 選到按鈕了");
  } 
    
  //方法二：透過 classList.contains
  //如果點擊到的元素 classList 內有包含 btn 
  if(e.target.classList.contains("btn")){
    console.log('classList.contains 選到按鈕了')
  }
})
```

原因是透過 getAttribute("class") 的方式選取 class 會回傳所有 class
同學可嘗試加入 console.log(e.target.getAttribute("class"))
就會發現輸出結果為 "btn btn-outline-primary"
而我們設置的判斷條件則是只需要判斷某一個 class 是否存在 
此時就比較適合使用 classList.contains 方法判斷是否包含某一個特定樣式

想了解更多關於 classList 可以使用的方法，歡迎參考此篇 👉 [文章](https://developer.mozilla.org/zh-TW/docs/Web/API/Element/classList)。

**closest**

當在複雜 HTML 結構中想透過 e.target 選取某個 Element ，卻都只能選到它的子層時，可以透過 closest 去取到自己想要的 Element ，
透過 closest  的方法，能很方便的取到自己想要的父層 Element ，範例如下：

HTML：
```html=
<ul class="list">
  <li>
    <input type="text">
    <span>123456789</span>
    <button type="button">按鈕</button>
  </li>
</ul>
```
JavaScript：
```jsx=
//透過 querySelector 選取 class list
const list = document.querySelector(".list");
//註冊監聽 list 的點擊事件
list.addEventListener("click", (e) => {
//單純監聽點擊到的元素本身 e.target
  console.log(e.target);
//透過 closest 方法並於括號內透過字串形式的方式，放入想選取到的標籤名稱
  console.log(e.target.closest("li"));
});
```
分別點選 input 、 span 、 button 的印出結果如下：

(一)單純使用 e.target
![](https://i.imgur.com/mEjShDV.png)

(二)使用 e.target.closest("li") 
![](https://i.imgur.com/ujEIVnC.png)

想了解更多關於 closest 可以如何使用，歡迎參考此篇 👉 [文章](https://developer.mozilla.org/zh-CN/docs/Web/API/Element/closest)。



---
### querySelectorAll

**知識點：**
> **querySelectorAll**
> **classList**

**querySelectorAll**

透過 querySelectorAll 可以選取多個元素，會回傳 nodeList ，操作上類似陣列，且 querySelectorAll 也可以使用陣列方法的 forEach ，參考如下：
HTML：
```html=
<ul class="list">
  <li>123</li>
  <li>456</li>
  <li>789</li>
</ul>
```
JavaScript：
```jsx=
const list = document.querySelectorAll(".list li");
list.forEach((item) => {
  console.log(item);
});
```
印出結果：
![](https://i.imgur.com/E8DPe74.png)

**classList**

可以透過 Element.classList 來新增、刪除或修改某 DOM 元素的 class 類別，範例如下： 
HTML：
```html=
<button type="button" class="btn btn-outline-primary">按鈕</button>
```
JavaScript：
```jsx=
//透過 querySelector 選取 class 為 btn 的元素
const btn = document.querySelector('.btn');

//透過 classList 的 remove 方法移除 btn 的 btn-outline-primary 這個 class 類別 
console.log(btn.classList.remove('btn-outline-primary'));
console.log(btn);// 輸出結果為 <button type="button" class="btn">按鈕</button>

//透過 classList 的 add 方法新增 btn的 class 類別 btn-outline-primary
console.log(btn.classList.add("btn-outline-primary"));
console.log(btn);// 輸出結果為 <button type="button" class="btn btn-outline-primary">按鈕</button>

```

---

### 鍵盤事件 - keyup

**知識點：**
> **鍵盤事件 - keyup**

**鍵盤事件 - keyup**

鍵盤事件 keyup 可以拿來偵測是否按下特定鍵盤，而 keyup 的觸發時機為當你按下特定鍵盤又放開的那刻：
```html=
<input type="text">
```
```jsx=
//透過 querySelector 選取 input 欄位
const input = document.querySelector('input');
//註冊監聽 input 欄位的 "keyup" 事件
input.addEventListener("keyup", function (e) {
    console.log(e);
  });
```
當我點擊 Enter 鍵觸發該 "keyup" 事件時，可以觀察到 Event 包含：

![](https://i.imgur.com/oyay5UJ.png)

該 "keyup" Event 內相當多的屬性，如果我們希望點擊到 Enter 時，可以觸發對應事件，可以透過以下方式：
```jsx=
//註冊監聽 input 欄位的 "keyup" 事件
input.addEventListener("keyup", function (e) {
    //如果屬性的 key 值為 "Enter" 
    if (e.key === "Enter") {
    //符合條件就執行大括號內程式碼
        console.log('我鍵盤按了 Enter ')
    }
});
```
想多了解鍵盤事件怎麼觸發，可以點擊此 [CodePen 檔案](https://codepen.io/denilsonsa/pen/epmoma)。


---
### .match()

**知識點：**
> **.match()**
> **.match() 搭配 filter**

**.match()**

`str.match()`括號內通常會放入一個正規表達式，當該字串與正規表達式的匹配結果符合時，它將回傳一個新陣列，而陣列內會放入符合的結果，範例如下：
```jsx=
//要比對的字串
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

//要找出範圍 A-E 
//g：比對該字串所有位置
//i：不去區分大小寫
//宣告一個變數賦予正規表達式
var regexp = /[A-E]/gi;
var matches_array = str.match(regexp);

console.log(matches_array);
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
```
以上範例程式碼取至 MDN，如果想更瞭解正規表達式歡迎點選 👉 [文章](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions)。

**.match() 搭配 filter**

`.match()`不僅能搭配正規表達式，還可以搭配 filter 來優化搜尋功能，範例如下：
HTML：
```html=
<!-- <input type="search"> 此 type 可專門拿來搜索-->
<h3>.match() 搭配 filter 搜尋</h3>
<input type="search">
<button type = "button">按鈕</button>
<ul></ul>
```
JavaScript：
```jsx=
const list = document.querySelector("ul");
const button = document.querySelector("button");
let data = [
  {
    作物名稱: "椰子"
  },
  {
    作物名稱: "釋迦"
  },
  {
    作物名稱: "藍莓-進口藍莓"
  }
];
//初始化，先將 data 的作物名稱渲染於畫面上
function renderData(showData) {
  let str = "";
  showData.forEach((item) => {
    str += `<li>${item.作物名稱}</li>`;
  });
  list.innerHTML = str;
}
renderData(data);
//監聽 button 按鈕的點擊事件
button.addEventListener("click", (e) => {
//透過 querySelector 選取 input 欄位
  const input = document.querySelector("input");
  let filterData = [];
  //透過 data 去跑 filter 並將結果賦予給 filterData
  filterData = data.filter((item) => {
  //回傳 .match 符合的匹配結果
    return item.作物名稱.match(input.value);
  });
  console.log(filterData)
  renderData(filterData);
});
```
顯示結果：

![](https://i.imgur.com/dmwiB88.png)

歡迎點選此 👉  [CodePen](https://codepen.io/jmkhsutp/pen/ZEypgYm?editors=1010) 玩看看唷！



---
### switch

**知識點：**
> **switch**
> **sort()**

**switch**
`switch` 後的小括號內會帶入一個表達式，並透過表達式的值去比對底下 case 後帶入的值是否符合該表達式回傳的值，符合的情況就會去執行 case 底下的條件，而每個 case 執行完後必須帶入 break ，才能終止程式碼繼續往下一個 case 執行，語法如下： 

語法：
```jsx=
switch (expression) {
  case value1:
        //當 expression 的值符合 value1
        //要執行的陳述句
    break;
  case value2:
        //當 expression 的值符合 value2
        //要執行的陳述句
    break;
  case valueN:
        //當 expression 的值符合 valueN
        //要執行的陳述句
    break;
  default:
        //當 expression 的值都不符合上述條件
        //要執行的陳述句
    break;
}
```

想了解表達式與陳述式為何，歡迎參考此篇 👉  [文章](https://wcc723.github.io/development/2020/09/17/js-expression/)

透過簡單的範例讓同學更了解 switch ：

HTML：
```jsx=
<select>
  <option value="蘋果">蘋果</option>
  <option value="香蕉">香蕉</option>
  <option value="水蜜桃">水蜜桃</option>
  <option value="雞腿飯">雞腿飯</option>
</select>
```
JavaScript:
```jsx=

let select = document.querySelector("select");
//監聽 select 的 "change" 事件
select.addEventListener("change", (e) => {
//比對是否為 change 更換到的元素的 value
  switch (e.target.value) {
    case "蘋果":
      console.log(e.target.value);//"蘋果"
      console.log("我是蘋果");
      break;
    case "香蕉":
      console.log(e.target.value);//"香蕉"
      console.log("我是香蕉");
      break;
    case "水蜜桃":
      console.log(e.target.value);//"水蜜桃"
      console.log("我是水蜜桃");
      break;
    default:
      console.log(e.target.value);//"雞腿飯"
      console.log("我不是蘋果/香蕉/水蜜桃");
      break;
  }
});
```
結果歡迎點選此 [CodePen](https://codepen.io/jmkhsutp/pen/OJgbRoQ?editors=1011) 嘗試看看，可以透過 Console 查看 Change 後的結果哦！

**sort()**

陣列方法 `sort()` 可以用來重新排列陣列中的元素，並返回原陣列。

`sort()` 可帶入參數 `compareFunction` ，且會根據 `compareFunction` 函式內帶入參數的比較結果，去進行排序。

如果使用 `compareFunction` 參數，並定義該函式內有參數  `a` 和 `b` 為被比較之兩元素，則：

- 若 `a` - `b` < 0， `a` 排在 `b` 前面。
- 若 `a` - `b`  = 0，則 `a` 與 `b` 皆不會改變彼此的順序，但會與其他全部的元素比較來排序。
- 若 `a` - `b`  > 0 ，則 `b` 排在 `a` 前面。

所以，比較函式會是以下形式：

```jsx=
let arr = [5, 2, 3, 4, 1, 7, 20, 10, 90, 6];
        //compareFunction
arr.sort(function (a, b) {
  return a - b;
});
// arr = [1, 2, 3, 4, 5, 6, 7, 10, 20, 90];
```

想了解更多關於陣列方法 sort() ，歡迎參考此篇   👉  [文章](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)。

