---
# System prepended metadata

title: javaScript 筆記

---




javaScript 筆記
===

# 觀念解釋

[ Coding style 培養好的寫程式語法](https://ithelp.ithome.com.tw/articles/10197116)

[關於 javascript 分號](https://eddychang.me/js-semicolon/)


[關於變數與一些javascript知識](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part3/var_const_naming.html)

[重新認識 JavaScript: Day 07 「比較」與自動轉型的規則](https://ithelp.ithome.com.tw/articles/10191254)

[null、undefined、NaN 的差異與檢查方式](https://sweeteason.pixnet.net/blog/post/43007183-javascript-%E5%9F%BA%E7%A4%8E%E6%89%93%E5%BA%95%E7%B3%BB%E5%88%97-%28%E4%BA%8C%29---%E9%97%9C%E6%96%BC-null%E3%80%81undefine)

# [新手不可不知的五個 JS 知識點](https://blog.happycoding.today/js-beginners-growth%ef%bd%9ciris-coding-newbie/?fbclid=IwAR3bFuP9ZKtN7Uh3ViRef6EBjITfETwXfLsrI_eS2CYMm_AL3F8G2ewdOgk)

# null 與 undefined 的差別
null 是有給值，只是用 null 清空值。
undefined 是還沒有給值。

# javaScript 的瀏覽器渲染行為
[參考瀏覽器怎麼解析整個程式碼的文件](https://)


 # 變數


* 用來存放資料的語法,會在記憶體建立一個空間存放值
* 可以存放字串、數值、布林、陣列、物件等等
* 數值可以放小數點、負值 例如：1.31459......或是 -10 等等。
* 目前宣告變數推薦使用 let

**javaScript 是一種弱型別語言。**
*程式語言有分強型別與弱型別，最主要的差異是強型別再宣告變數時就要跟這個變數講你是什麼型態的資料。
EX：字串、布林、數字.....
但是弱型別不用，只需要給一個資料，根據資料會再去判斷型態。
EX：你的資料是數字就是 Number 你的資料是 "我是字串" 有加引號就是字串。*

# 運算式與運算子
只要是跟字串相加，最後就會被轉型為字串
例如：
```
"10"+ 10 = 1010;
```
但是減法、乘法、除法都沒變。
可以參考這篇文章 [運算式與運算子](https://ithelp.ithome.com.tw/articles/10191180)

# 錯誤的變數命名
* 變數第一個不能是數字
* 不能把 jS 保留字當作變數 [保留字表](https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/272620/)

# 三種變數宣告 var 、let、const 的差別
* var 可以隨意更改的變數。（不嚴謹）
* let 可以隨意更改的區塊或區域變數。（嚴謹）
* const 宣告一個只可讀取的不可變常數

# 字串處理實用方法
* length 檢查長度(空白也算)
* trim 過濾掉空白

[字串處理實用方法程式範例](https://codepen.io/hong-wei/pen/VwKJdVb?editors=0011)

# 字串轉數字的方法

[字串轉數字程式範例](https://codepen.io/hong-wei/pen/WNoQaqQ?editors=0011)

使用 `parseInt() ` 可以將字串轉成數字

例如：
```
let a = "1";

console.log(a+1)  //結果為 字串 11 
```

改用 parseInt() 

```
let a = "1";
a = parseInt("1");
console.log(a+1)  //結果為數字 2
```

# 數字轉字串方法

[數字轉字串程式範例](https://codepen.io/hong-wei/pen/rNWOQNG?editors=0011)
使用 `toString(); `帶入方式與 parseInt() 不同需留意。

```
let a = 9;
a = a.toString();


console.log(typeof a); //驗證變字串了
console.log(a+1);  //91
```

# 樣板字面值教學

[使用樣板程式範例](https://codepen.io/hong-wei/pen/PoGrBGy?editors=0011)

# ES6
為了解決 ES5 程式碼上面比較容易出錯或解決常見問題的語法，所延伸出來更新的 javaScript 語法可以想像成 CSS2 變到 CSS3 增加更多新功能的語言。

#  let - if、function 用法

let 放在區塊內也就是 function( ){ 這裡就是區塊 }
這樣就不會污染到全域變數。
# const 
他是一個有唯獨特性的變數，無法日後賦值改變他，但是如果是物件或是陣列型態是可以改變值的。

```js
const a = "小明"
a = "小王"

//結果還是小明，不會被改變
```
但如果是陣列貨物件是可以取屬性值去改變的

```js
const a = {
 name: "小明"
}

a.name ="小王"

//結果會變成{name:"小王"}

如果想要把物件變成唯獨不可以被改變要多寫這一行
object.freeze(a);
//凍結物件的意思
```

# let 與 const的使用時機
let 與 const 都是區域變數不會變成全域變數所以不會寫在  windons 裡面。

另外如果今天我們這樣寫：

```js
console.log(a) //未定義
var a = 1;
console.log(a) //1

//因為 var 會變全域變數所以會把權重往上提高不會出錯，只是未定義，但如果今天是 let 或 const 就會出錯。
```

## let 可以重新給值，const 無法重新給值
如果有變數的數值是會隨時變動的用 let 建立變數，如果數值固定不動也不想被更動使用 const
![](https://i.imgur.com/w4Ti7Pw.jpg)


## JS內建型別（Built-in Types）
>JavaScript 定義了以下七種內建型別



```js
//number 數字
123  
                                        
//string 字串
'Hello' 

// boolean 布林
true,false 

//object 物件
 { name: 'Jack' }、[1, 2, 3]、function foo() 、{ ... }          
//空值
null

//未定義
undefined

symbol

```

上面這些內建型別又細分兩大類

<font color="blue">1. 基本型別（primitives）</font>
<font color="blue">2. 物件型別（object）</font>

物件型別就是物件與其子型別（subtype），例如：物件、陣列、函式、日期等。



# 函式
函式可以把它當作寫一個功能在裡面，需要的時候就執行它！
[函式撰寫程式範例](https://codepen.io/hong-wei/pen/eYBVJPy?editors=0011)

# 函式內可以再放函式
如果今天一個函式有機會被重複使用到，可以獨立出來建立一個函式，當需要時再放進要執行它的函式內就可以～
好處是當會重複用到的地方，不用重複撰寫，另外也可以針對這個會重複用到的函式進行修改。

[函式內放函式程式範例](https://codepen.io/hong-wei/pen/OJbQMGM?editors=1011)

# 函式中的參數
在函式中可以放參數，就像下方的寫法
![](https://i.imgur.com/UQeeLna.jpg)

參數可以放不只一個，例如這樣的寫法
```
function myDay(num,num2){
  console.log(num);
  console.log(num2);
};


//執行時可以放參數
myDay(1,2); 
myDay(3,4);
```
[帶入多個參數程式範例](https://codepen.io/hong-wei/pen/vYydGGE?editors=0011)

# 參數只會存活在大括號中
參數只會存活在大括號中，如下圖所示！
要在呼叫必須在執行函式中放入要帶入的參數
[![](https://i.imgur.com/YfawgsW.jpg)
](https://)


# 透過函式寫兩個數字相加工具
[數字相加工具程式範例](https://codepen.io/hong-wei/pen/zYoRBGY?editors=0011)


# 函式中的 return

return 可以把函式內的運算方法回傳到函式內，真正的讓函式內的運算方式被儲存下來，例如下面這張圖：
[return 程式範例](https://codepen.io/hong-wei/pen/GRNxmaN)
![](https://i.imgur.com/oQAM5GV.jpg)

# return 可以放在變數內
[return 可以放在變數內程式範例](https://codepen.io/hong-wei/pen/GRNxmaN?editors=1011)

# return 可以寫很多個
一個函式中可以放很多的 return 不過第一個 return 執行後，後面的程式就不會跑了，會被中斷！

[return 中斷後面程式範例](https://codepen.io/hong-wei/pen/NWbYjQX?editors=0011)

# return 可以有很多個
下面的程式範例，說明 return 可以有多個！不過一但符合條件後面的程式就不會繼續執行！

[return 多個的程式使用範例](https://codepen.io/hong-wei/pen/MWbVowz?editors=1011)




## JS 符號意思
`·`  一個點指的是獲取一個屬性或是方法的意思。
```js
function(){} 
//這是一個函式的寫法可以命名也可以不命名()代表之後要帶的值
//無論之後要不要帶值進去都要寫。
``` 


補充說明：
今天有一個函式是這樣寫()內就是要填之後我要帶進去的東西。

```js
function eat(name){
  console.log('我的名字是'+ name);
}

//呼叫函式這個()內就是要填要放進去的東西。
eat(小瑋);
```

## 全域與區域的意思
寫在function內的變數是區域變數，寫在外面則是全域變數，區域變數跑完後你在外面要在呼叫他是沒用的。

```js
fuction(){  
var car = BMW;   //寫在這就是區域變數
}

var car = BMW;   //寫在這就是全域變數
```



## hoisting觀念
在 javeScript 內你可以先呼叫函式  `exmaple()` 在寫函式是可以執行成功的！
原因是因為在 javeScript 內他會自動把函式的權重拉到最高所以即便順序錯了,依然可以執行。



# 陣列、物件、forEach


陣列的寫法如下
```js
var array = ["資料一","資料二","資料三"]
//陣列內不同的資料之間要用 , 隔開

//每筆資料都要加雙引號，如果不加裡面就是會放變數例如
var array = [變數]
```

# 陣列 push 新增在後方
可以在陣列後方再增加新的資料，[push 程式範例](https://codepen.io/hong-wei/pen/yLVoKPX?editors=1011)。
# 陣列 unshift 新增在前方
可以在陣列前方新增資料，[unshift 程式範例](https://codepen.io/hong-wei/pen/ZEBJxra?editors=1011)

# 陣列 pop 刪除後方資料
可以再刪除陣列後方最後一筆資料 [pop 使用程式範例](https://codepen.io/hong-wei/pen/VwmzXxN?editors=1011)

# 陣列 shift 刪除前方資料
可以刪除陣列前方第一筆資料 [shift 使用程式範例](https://codepen.io/hong-wei/pen/mdOMxjd?editors=1011)

# 陣列 splice 可以刪除指定資料
可以刪除陣列中指定的資料位置 [splice 使用程式範例](https://codepen.io/hong-wei/pen/XWNaEoY?editors=1011)

**splice刪除的方式**
splice('起始位置序號','包含自己開始要刪除幾個')
例如 splice(1,1)
就是指序號第 1 個開始從自己開始刪除數量1個。


# 陣列的其他注意事項
空陣列可以像下方這樣把序號欄位直接給值，如果跳過序號欄位沒給值，那個地方會變成 undefined 不過還是佔一個位置，所以總長度不變。

[程式連結](https://codepen.io/hong-wei/pen/BaQdrLa?editors=1011)
```
let band = [];
band[0] = "賓士";
band[1] = "寶馬";
band[2] = "風田";
band[4] = "野馬";
console.log(band);//為依序填寫的地方會變 undefined
console.log(band.length); //但是 undefined 也會算一個位置，所以總長度不變
```
# 物件
物件的格式如下：
用大括號 { } 裡面放屬性與值，最後一個屬性的值不用逗號。

```
let home ={
  motherName : "marry",
  sonName: "AWEI",
  car:1
}
```
# 選取物件
先選取物件名稱，在用點選取到屬性名稱就可以取得物件內屬性的值
```
let home ={
  motherName : "marry",
  sonName: "AWEI",
  car:1
}

console.log(home.car);
```
[選取物件程式範例](https://codepen.io/hong-wei/pen/gOLGgmJ?editors=0011)
# 新增物件屬性

如果屬性一開始就存在，則以上的語法會更新該屬性的值; 反之則會建立一個新的屬性。


```
let home = {};//空物件


//把資料新增到物件的方式
home.motherName = "MALI";
home.sonName = "AWEI";
home.car = 3;

console.log(home);
```
[在物件新增屬性程式範例](https://codepen.io/hong-wei/pen/ZEBXBvY?editors=0011)

# 修改物件值
直接選取物件屬性用 = 賦予新值
```
let home = {
  motherName:"MALI",
  sonNmae:"AWEI",
  car:3
};

//修改物件的值
//修改名字
home.motherName = "Lisa"
//增加數量
home.car += 1;
home.car = home.car+1;

console.log(home);
```
[修改物件值程式範例](https://codepen.io/hong-wei/pen/ZEBXBoG?editors=0011)

# 刪除物件資料
選取要刪除的物件資料並在前方加上 delete 即可！

```
let home = {
  motherName:"MALI",
  sonName:"AWEI",
  car:3
};

// 刪除物件資料直接在前方加上 delete
delete home.sonName;
delete home.motherName;

console.log(home);
// 已經被刪除的資料可以去檢查會變 undefined
console.log(home.sonName);
```
[刪除物件程式範例](https://codepen.io/hong-wei/pen/ExNwNpg?editors=0011)

# 讀取物件資料的其他方式
可以用 [ ] 的方式來做讀取
[讀取物件資料程式範例](https://codepen.io/hong-wei/pen/XWNeNyK?editors=0011)

之所以可以改用 [ ] 取值得原因是因為有時候我們的物件格式 JSON 他的屬性值是長這樣 "001" 當遇到這種屬性是數字的資料，如果用 home.001 會出錯，所以改用 home['001'] 就能正確讀取！

[使用 [ ] 程式範例](https://codepen.io/hong-wei/pen/VwmMmOX?editors=0011)


# 陣列與物件的差別
>資料如果是同類型就用陣列但是如果一個資料有很多的屬性那就是用物件

範例如下：
``` js
var home = ["大樓","公寓"，"華廈"] //陣列

var home ={
    "type": "大樓", // "屬性"：值
    "price" : 1000,
    "peple": 6,
    "car": true
}

//最後一筆資料不用加 , 逗號
```

# 陣列與物件整合運用

陣列裡面也可以放物件，可以參考[陣列包物件程式碼](https://codepen.io/hong-wei/pen/poNWOor?editors=0011)

# 一次搞懂陣列與物件混合讀取教學

要讀取陣列中物件內的資料，可以從最外圍開始抓取慢慢依序抓到你要的資料
方式如下：
例如要讀取魏小姐的名字。

先抓變數名稱 market 再抓 資料在陣列中的序號[1]再用點去選取要讀取的屬性名稱 bossName 即可抓到值。

```
let market = [
  {
    bossName:"王先生",
    appleNum:300,
    bananaNum:200
  },
  {
    bossName:"魏小姐",
    appleNum:600,
    bananaNum:800
  }
];

//要讀取魏小姐請問怎麼做？
console.log(market[1].bossName);
```
[陣列中讀取物件程式範例](https://codepen.io/hong-wei/pen/xxRXaVm?editors=0011)


# 物件包物件寫法

陣列內可以放物件內可以在放物件，取值得方式就是從最外層按照順去往內讀取！

[物件包物件寫法與取值程式範例](https://codepen.io/hong-wei/pen/vYyeVgZ?editors=0011)



# 物件包物件與陣列讀取流程
遇到一個 JSON 資料，他的資料型態有物件有包含陣列取值的方式就是遇到物件用點，遇到陣列用[ ]裡面填資料的序號位置。

[物件包物件與陣列讀取流程程式範例](https://codepen.io/hong-wei/pen/ExNwqYR?editors=0011)

# 在物件內新增、修改、取得屬性的方法有以下兩種:

1. 點記法 (Dot notation)

```js=
let obj = {};
obj.key = value;  // 新增或修改
console.log(obj.key); // 取得
```

2. 括弧記法 (Bracket notation)
```js=
let obj = {};

// 當 key 的值帶有小數點或是空格時可以使用 (如 -- some.data)，記得要加上引號 (單引號或雙引號皆可)
obj['key'] = value;  // 新增或修改
console.log(obj['key']); // 取得
```
[物件新增、修改、取得屬性的幾種方式程式範例](https://codepen.io/hong-wei/pen/XWNYbbR?editors=0011)

如果屬性一開始就存在，則以上的語法會更新該屬性的值; 反之則會建立一個新的屬性。
# 物件搭配 if 寫法
[物件搭配 if 寫法程式範例](https://codepen.io/hong-wei/pen/OJbOLYB?editors=0011)


# 陣列物件搭配 if 流程判斷練習
[陣列物件搭配 if 流程判斷程式範例](https://codepen.io/hong-wei/pen/eYBeYNZ?editors=0011)

# 只要抓取 JSON 內的部分資料方式
一個 JSON 內有許多的資料，有時候我們可能只要裡面的陣列資料，針對這一塊資料去單獨處理，此時做法可以這樣做！

把要抓取的資料，先透過一個變數存起來，之後再透過這個變數去處理裡面的資料，可以參考 [使用的程式範例](https://codepen.io/hong-wei/pen/eYBGqWK?editors=0011)。


# 處理陣列的方式
處理陣列有很多的方法，以下都是處理陣列的函式：

* push
* length
* filter()
* forEach()
* map()
* every()
* some()
* reduch()




# 為什麼要用 forEach
請問如果要把這個陣列當中的數字相加你會怎麼做？

```=javascript
let data = [1,2,3];
```

按照之前我們學的 [陣列取值方式](https://codepen.io/hong-wei/pen/vYyvZza?editors=1011) 我們會這樣做

```=javascript
console.log(data[0]+data[1]+data[2])
//答案是 6
```
可是如果今天陣列有幾百幾千筆，如果還用這種方式取值就太麻煩也沒有效率了！

這時 forEach 就可以簡化取值的方式。



# forEach 寫法
![](https://i.imgur.com/x9bjVGT.jpg)

[forEach 寫法程式範例](https://codepen.io/hong-wei/pen/BaQvZwM)

*PS.裡面的參數名字可以自行替換，例如 item 可以改成 i 但是他要取的值都是不變的。*

# forEach 取值注意事項

如果 API 或 JSON 格式欄位名稱是中文，盡量用以下方式取值，避免出現不可預期的錯誤。
以下是範例：

```js
[
{
 地點："台北市",
 節目名稱："隱藏版的大明星",
 票價: 200
}
]
```
```js
//過去我們要取地點名稱會用這個方式
item.地點
//建議遇到中文或是奇怪的字元就改用["裡面放屬性名稱"]取代 . 
像是這樣 item["地點"]
```
[參考影片：大神來六角 2020 「陣列與物件、forEach篇」影片 1:18分開始講解](https://courses.hexschool.com/courses/2020/lectures/19626837)


# 利用 forEach 加總數字
前面有提到如何利用 forEach 來加總陣列中的數字可以這樣寫！

```javascript=
let data = [1,2,3];
//把取數字
let total = 0;

data.forEach(function(item){
  total += item;
})

console.log(total);   //6
```

[forEach 加總數字程式範例](https://codepen.io/hong-wei/pen/YzpdxZg?editors=0011)


# 利用 forEach 抓出偶數的數字，並丟到新的陣列中

此範例展示怎麼抓出哪些數值是偶數，並且把它丟到新的陣列之中...

[forEach 抓出偶數的數字，並丟到新的陣列中程式範例](https://codepen.io/hong-wei/pen/xxRmLaQ?editors=0011)


# forEach 男女人數計算機-透過物件整合資料

今天要計算男女人數的比例，如果都要建立 
```
let woman = 0;
let male = 0;
```
每記錄一個資料都要建立一個變數，這樣變數就會散落各處！
今天可以把相同要計算的資料用一個陣列包起來，就像下方這個範例

[男女人數計算機-透過物件整合資料](https://codepen.io/hong-wei/pen/BapBKar?editors=0011)

# 使用 forEach 計算充電站免費與付費的數量

[統計高雄充電站免費與投幣式數量程式範例](https://codepen.io/hong-wei/pen/WNReyPB?editors=0011)

[統計全台灣充電站付費與免費把資料丟到陣列中程式範例](https://codepen.io/hong-wei/pen/rNjBZmZ?editors=0011)


# 處理陣列的方式 filter() 與 map()

跟 forEach 都是處理陣列的方式，但不同的是這兩個不會去改變原有的陣列，而是會產生新的陣列所以在函式內都需要使用 `return`

# filter() 與 map() 使用時機

* 假設一pchome搜尋商品設定10000以下，可以將廠品的資料設定filter return amount <= 10000

* 假設二，如果我要找出公司裡面任職時間超過10年以上的員工，可以打
```
staff.filter(function(item){
 return item.seniority > 10
})
```
filter要回傳一個boolean值
講簡單一點，filter就是對陣列做批量的if判斷，true就回傳該值/物件，false就篩掉。

[介紹 filter()與 map()相關文章](https://ithelp.ithome.com.tw/articles/10229458)

# 撰寫查詢充電站是否免費與新增充電站程式範例
[撰寫查詢充電站是否免費與新增充電站程式範例](https://codepen.io/hong-wei/pen/rNjaGqX)


# 流程控制判斷
可以用 `if else` 或是用 `if else if`
`if else` 只能判斷單一條件
`if else if ` 可以判斷多個條件，另外 `else if` 後面可以不加 `else` 沒有關係。


# JS中的真值與假值的認定

在一個 JS邏輯判斷中，如果題目是這樣！
```js=
let ProductInfo = {
    Price: 1000,  // 購買價格
    coupons:[
      {
          due_date: "2021-10-15",
          id: 123,
          is_enabled: 0,
          percent: 0.7,
          title: "特惠七折",
      },
      {
          due_date: "2021-08-08",
          id: 456,
          is_enabled: 1,
          percent: 0.5,    // 折扣比例
          title: "特惠五折",
      }
    ]
}

/* 請取得 coupons 陣列中 id 為 456 的 percent，並賦值給 discountPercent */
let discountPercent;
discountPercent = ProductInfo.coupons[1].percent;

/* 請取得 coupons 陣列中 id 為 456 的 title，並賦值給 title */
let title;
title = ProductInfo.coupons[1].title;
/* 請取得 coupons 陣列中 id 為 456 的 is_enabled，並填入以下 if 判斷式中; 
如果判斷為 true，則對「購買價格」進行折扣*/

if(ProductInfo.coupons[1].is_enabled ){
    ProductInfo.Price *= discountPercent;
    console.log(`優惠券已啟用，${title}`);
}else {
    console.log("優惠券未啟用");
}

console.log(`購買價格 ${ProductInfo.Price}`);

```

其中可以發現在最後判斷是否 is_enabled 為 true 時，明明題目的is_enabled 就是1，但在判斷時不需要寫 ProductInfo.coupons[1].is_enabled === 1 直接寫 ProductInfo.coupons[1].is_enabled 就好，原因是 1 會直接被 JavaScript 當作是 true。


這邊可以參考 JavaScript 中的 [真值](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy) 與 [假值](https://developer.mozilla.org/zh-CN/docs/Glossary/Falsy) 介紹文章。

# 比較運算子

`  =   `  指定用途
`  == `  是否相符 <font  color="blue">比較不嚴謹，值對了就可以，它會自動轉型別</font>
`!==` 是否不符
`===` 嚴謹的判斷 <font  color="blue">除了值對，型別也要對。</font>
`  >= `  大於等於   <font color="blue">只要其中一個符合就是對的。</font> 

## 邏輯運算子
`&&` 所有條件都要符合才是對的。
`||` 所有條件只要其中一個符合就對。
`！` 上面的條件的相反就加這個符號。

## 註記判斷與邏輯相關延伸閱讀


:::info
[判斷筆記](https://medium.com/%E9%A6%AC%E6%A0%BC%E8%95%BE%E7%89%B9%E7%9A%84%E5%86%92%E9%9A%AA%E8%80%85%E6%97%A5%E8%AA%8C/js-%E5%88%A4%E6%96%B7%E7%AD%86%E8%A8%98-%E9%81%8B%E7%AE%97%E5%AD%90-if-switch-a9f5e535835b)
:::

# JS 累加的概念 a++、a-- 一次搞懂
可以直接加上一個數值的寫法
 
```
let a = 10;
a += 50; 
//結果為 60
```
如果想要每次都只加一個，或減一個就寫 a++ 或 a--
僅能依序增減，不能指定數字增減
```
let a = 10;
a++ // 結果為 11
a++ // 結果為 12
a++ // 結果為 13
```
# 迴圈

>可以依指定的次數重覆執行一段程式
:::info
[迴圈更詳細的介紹](https://ithelp.ithome.com.tw/articles/10191453)
:::

```js
for (var i=0;1<10;i++){}
//for(初始條件;條件;更新條件)
```

for迴圈內的更新條件
不管是 i = i+1 或是 i+=1 或是 i++ 都是累加的意思。
通常寫 i++ 也可以是 i--

## JSON
json是一種資料交換格式，很多程式語言都可以用這個格式

[關於JSON的動畫影片介紹](https://zh.wikipedia.org/wiki/JSON)



# DOM 的介紹

>文件物件模型（Document Object Model, DOM）是 HTML、XML 和 SVG 文件的程式介面。它提供了一個文件（樹）的結構化表示法，並定義讓程式可以存取並改變文件架構、風格和內容的方法，簡單說DOM就是瀏覽器會把程式碼把一個一個解析出來變成一個個的物件結構。

:::info
[關於DOM的影片介紹](https://www.zhihu.com/question/34219998)
:::

```js
document.getElementById('title')

//文件.去抓這個文件中的ID ('ID的名字')
```
# JS 選取器
使用 querySelector 可以選擇 DOM 元素的方式！
[使用選擇器程式範例](https://codepen.io/hong-wei/pen/zYoapXo?editors=1011)


# querySelector ＆ querySelectorAll
這個語法可以選取單一元素，就像選CSS選擇器這樣
但如果要選取網頁上所有的元素就要用 `querySelectorAll`
> 注意！
如果用 querySelector 只會選到第一個指定的 class 所以要全部選取就要用 uerySelectorAll，或是用 querySelector但要去選取父元素（最終作業遇到的問題）

使用 querySelector 會回傳 DOM
使用 querySelectorAll 會回傳 陣列
[使用 querySelectorAll 分別增加屬性的範例](https://codepen.io/hong-wei/pen/oNYyOWY)


# querySelector 與 getElementById的差異
[querySelector 與 getElementById的差異介紹文章](https://swoole.app/2017/08/08/querySelector%E5%92%8CgetElementById%E6%96%B9%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB/)

# textContent 選取元素後更改內容
可以利用下列語法，把元素選取起來更改裡面的內容
```
let el = document.querySelector('h1');
el.textContent = "標題改囉！";
```
[textContent 程式使用範例](https://codepen.io/hong-wei/pen/LYbrQPO?editors=1011)

# innerHTML 與 createElement

有兩個語法可以用 js 去操作 html 

`innerHTML` 變字串

>方法：組完字串後，傳進語法進行渲染
優點：效能快
缺點：有資安風險，要確保來源沒問題

跟 textContent 不同喔，textContent 是把原本的內容改寫
innerHTML 是刪掉原本的內容，放進新的標籤與內容。

[innerHTML 程式使用範例](https://codepen.io/hong-wei/pen/bGBKZRq?editors=1010)

# innerHTML 還可以放變數
innerHTML 內除了可以放組一段標籤與內容外，還可以把變數放進去！
[innerHTML 放變數程式範例](https://codepen.io/hong-wei/pen/bGBKZRq?editors=1011)

# textContent 與 innerHTML 差異

> textCotent 僅是增加文字內容
> innerHTML  會真的產生一個可以使用的標籤

[textContent 與 innerHTML 差異程式範例](https://codepen.io/hong-wei/pen/jOVKROp?editors=1010)


`createElement`

>方法：以 DOM 節點來處理
優點：安全性高
缺點：效能差

總結：如果需要使用者輸入資料的就用 <font color='#5580f4'>createElement</font>


# setAttribute 增加 HTML 
使用 setAttribute('放要增加的屬性名稱','屬性值')；
[使用 setAttribute 範例程式碼](https://codepen.io/hong-wei/pen/XWNYQjr)

```=JavaScritp
//選取 a 標籤
let el = document.querySelector('a');

//增加一個屬性，連到 google 網址
el.setAttribute('href','https://www.google.com.tw/');
```

# .innerHTML、.textContent、.getAttribute 取值方法

getAttribute 是取值的方式

innerHTML 會選取到指定 **物件內** 的標籤

textContent 會選取到指定 **物件內** 的文字內容

[.innerHTML、.textContent、.getAttribute 取值方法程式範例](https://codepen.io/hong-wei/pen/xxRzePV?editors=1011)


# 表單元素取值方式

[表單元素取值方式範例程式碼](https://codepen.io/hong-wei/pen/yLVErRB?editors=1011)

# event 事件

用來觀察使用者在網頁上做了哪些事情，做了指定事件就讓程式做出反應，這邊有兩個方法可以達成。

`onclick` 比較舊的寫法，只能偵測最後一個事件無法連續下多個事件。
`addEventListener`（監聽事件）好處是可以下好幾個事件進去。


# addEventListener 監聽事件

建議的作法是使用 addEventListener()，因為它可以對一個 DOM 元素同時綁定多個事件處理函數。
以下介紹常用的三種參數:

`target.addEventListener("事件型態", 事件處理函數, 選項);`

1. 事件型態: 包含前述的 click, change, mousemove 等。
1. 事件處理函數: 觸發事件時所執行的函式。
1. 選項: 選擇性加入一些額外的事件監聽設定，在此先略過，之後的課堂會介紹。

# addEventListener 寫一個加減法工具

[加減法工具程式範例](https://codepen.io/hong-wei/pen/xxRQPWP?editors=1010)


# [KeyCode 點擊鍵盤發射火箭](https://codepen.io/hong-wei/pen/VwaJGQj)


# function(e) 裡面的 e 是什麼？

[關於 function(e) 裡面 e 的解釋](https://ithelp.ithome.com.tw/articles/10192015)

其實可以想成當你點擊某個元素後他會捕捉，你點擊到這個元素後他會把所有的資訊包成一個物件，你可以使用物件選取方式去取得你要的值。

**概念類似這張圖**

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

[function(e) 程式範例觀看](https://codepen.io/hong-wei/pen/WNoYXaQ?editors=1010)
# Event Bubbling、Event Capturing 差異
`false` (事件氣泡 event Bubbling) 從指定元素往外找，大部分都是用這個因為你只想要你點的那個地方有先有反應就中止了，不要去觸發其他的事件。

>延伸閱讀參考: 『JS學徒學徒event事件篇-Event Bubbling、Event Capturing 差異』

`true` (事件捕捉 event capturing)從最外層往內找到指定元素。

`stopPropagation` 可以中止冒泡事件

# preventDefault
`preventDefault`  取消元素預設的屬性，比方說點擊 a 標籤連結原本會連到外部連結，變的不會發生這件事。
[使用 preventDefault 程式範例](https://codepen.io/hong-wei/pen/YzpRYwb?editors=1010)

# e-target
`e-target` 可以得知目前點擊的位置是哪裡。


[延伸閱讀 關於事件傳遞機制的圖文說明](https://blog.techbridge.cc/2017/07/15/javascript-event-propagation/)

# localStorage 瀏覽器資料儲存


>介紹 [什麼是locaStorage ](https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/232745/)

## 基本操作

```js
setitem （'名稱','數值'）; //這是放置資料到儲存庫的語法
```  
```js
getitem （'名稱'）; //這是去資料庫取數值的寫法，只需帶入名稱
```

## 透過 JSON.parse、JSON.stringify 來編譯資料

因為 localStorage 只能以字串方式進行儲存,所以會需要用 JSON.stringify 轉成陣列存在瀏覽器的資料庫內，要方便取用也要把資料轉成陣列才行，轉陣列要用 `JSON.parse`


程式解釋如下圖：
```js
var taiwan = [ { name : '小王' },{ name : '小英' } ] ;
// 此為JSON資料

var taiwanString = JSON.stringify(taiwan) ;
// 將資料轉為字串，以至能夠存取至 localStorage


localStorage.setItem( 'leader' , taiwanString); 
// 將編譯後的字串存儲

var data = localStorage.getItem( taiwanString ); 
// 取得位於 localStorage 編譯過後的字串資料

var dataAry = JSON.parse( data ); 
// 將取得的資料轉為 array 以便操作


```

## 透過dataset讀取自訂資料

我們可以直接在 HTML 標籤內自己定義一個標籤 data-自己取名字，用來之後直接呼叫這個標籤的內容。



# 瀏覽器功能探索 (BOM)


> 簡言之，我們也可以透過一些語法操作瀏覽器上面的資訊例如：
* history    <font color="#5580f4">可以實作上一頁或下一頁功能</font>
* frames 
* location <font color="#5580f4">可以更改網址</font>
* DOM  <font color="#5580f4">最常操作的 DOM 元素也是其中之一</font>
* screen <font color="#5580f4">可以去判斷瀏覽器的大小</font>
* navigator <font color="#5580f4">可以檢查目前是否有網路</font>

### 在window.open 與 a href 的差別
在於 window.open可以用在比較私密的連結上例如：票卷、線上銀行交易等較專屬私密連結功能，他無法右鍵另存網址也無法開啟新分頁。

[window.open 與 a href 的差別範例](https://codepen.io/hong-wei/pen/pogoePK)

# JS 開發邏輯


可以先把要完成的任務分三個

* 資料 - Model
例如：取資料、刪除資料等等....

* 事件 - Event
例如：addEventListener 或是使用者有跟畫面做互動的事情都算事件，如點擊、滑鼠滑過、網頁重新載入....。

* 介面 - View
例如：innerHTML 、 createElement 這些語法再畫面創造一個東西或是改變畫面等等都是處理介面。

基本上所有的開發都可以去遵循這個初步的方法，接著就是把學過的各種語法組成可以處理的程式碼，再去組裝即可。

# AJAX 

# 什麼是 AJAX ？
AJAX 是「Asynchronous JavaScript and XML」（非同步的 JavaScript 與 XML 技術）的縮寫，簡單說就是網頁不用重新整理，就能即時地透過瀏覽器去跟伺服器溝通，撈出資料。

>一種透過瀏覽器跟遠端伺服器要資料的方法。


# HTTP 狀態碼
HTTP 狀態碼表明一個 HTTP 要求是否已經被完成。回應分為五種：

* 資訊回應 (Informational responses, 100–199)
* 成功回應 (Successful responses, 200–299)
* 重定向 (Redirects, 300–399)
* 用戶端錯誤 (Client errors, 400–499)
* 伺服器端錯誤 (Server errors, 500–599)

>最常見的還是 200 的成功回應與 404 代表用戶端找不到資料。

>304 代表資料從記憶體撈取的因為這個資料之前有被開啟過，有先存到記憶體，如果不想從記憶體撈取可以清除快取（在開發人員工具下，長按著重新整理網頁按鈕就有下拉選單可以選清除快取並強制重新載入）。



[更多詳細的 Http 狀態碼解釋](https://blog.miniasp.com/post/2009/01/16/Web-developer-should-know-about-HTTP-Status-Code)


# HTTP 狀態碼教學 ([參考章節](https://courses.hexschool.com/courses/1289881/lectures/31133285))
---
學會看 HTTP 狀態碼是寫網頁很重要的一個能力，狀態碼所代表的訊息可以讓我們了解一個 HTTP 請求是否已經被完成。同學可以參考 [這篇文章](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status) 深入了解狀態碼的種類。

這邊替大家整理一些使用 AJAX 比較常遇到、需要了解的狀態碼訊息:

1. **成功回應 (Successful responses, 200–299)**
這區間的狀態碼表示伺服器有成功接收到用戶端要求。以 AJAX 的串接為例，如果回傳的 **status 為 200**，則代表有成功接收到資料。

2. **用戶端錯誤 (Client errors, 400–499)**
這區間的狀態碼表示有錯誤發生，且錯誤來自於「用戶端」。以 AJAX 的串接為例，
    * 回傳的 **status 為 400**，表示遠端伺服器接收到無效語法、無法理解請求，因此需要檢查程式碼有無寫錯的地方。 
    * 回傳的 **status 為 403**, 表示禁止使用，這代表用戶端沒有訪問權限，因此沒辦法成功串接資料。 
    * 回傳的 **status 404**，表示找不到檔案資料。


3. **伺服器端錯誤 (Server errors, 500–599)**
如果發生狀態碼為 **5xx** 的錯誤，則表示錯誤發生跟「遠端伺服器」有關，此時就需要跟後端工程師進行協調了。



如果要透過瀏覽器跟伺服器要資料要先建立一個語法 

```js
var xhr = new XMLHttpRequest(); //變數名稱自己定義
```
```js
xhr.open('get','https://example.json',true)

//解釋
xhr.open('格式','要讀取的網址',同步或非同步)

//格式又分
get 讀取資料
post 傳送資料到伺服器（ex:帳號驗證）
```
```js
xhr.send(); //要傳送的資料 （）內放資料。
```
>補充知識

readyState 狀態
`0 產生了一個 XMLHttpRequest 但還沒有連結你要撈的資料` 
`1 你用了open(),但還沒把資料傳過去` 
`2 偵測到你有用 send` 
`3 loading 下載中` 
`4 已撈到資料，數據已完全接受到` 




## AJAX 延伸閱讀
[我每天都接一個API系列 ](https://ithelp.ithome.com.tw/articles/10192204)
[必讀！輕鬆理解 Ajax 與跨來源請求-有提到 XMLHttpRequest 和 CORS](http://huli.logdown.com/posts/2223581-ajax-and-cors)



# 網路請求套件 axios 
在做網路請求方式時，可以使用 JS 原生的寫法
* XMLHttpRequest
* Fetch

也可以使用成熟的套件 **axios** 這個套件也是基於 XMLHttpRequest 的方式去撰寫的，好處是程式碼更簡潔。

# axios 環境安裝
可以直接使用 CDN 方式載入他的 JS 檔
記得套件累的 JS 都放在自己寫的 JS 檔的前面。
```=javascript
 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
 ```

# axios 語法結構
![](https://i.imgur.com/WIYLyvJ.jpg)

# axios 非同步觀念
![](https://i.imgur.com/iro3ORR.jpg)


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

使用 post 是把有夾帶資料的請求送出去，在這個資料有兩個資訊

* header
* content

在 header 內有四種請求方式
# application/x-www-form-urlencoded（傳送 HTML 表單的請求）

這種 POST 提交數據的方式很常見，它是屬於瀏覽器 <form> 表單的原生提交方式 (也就是說，如果表單沒有設定 enctype 屬性，默認就會用這種方式提交)。

(以下是補充介紹，可以先看過去就好)
值得注意的是，它會將提交的數據按照 key1=val1&key2=val2 的方式進行 URL 編碼。

# application/json (axios 預設請求方式，但可以更改)
因為 JSON 規範現在很流行，這種提交方式也已經非常普遍。這表示傳遞的數據是 JSON 格式 ，課程中所使用的 API 也是使用這種 Content-Type。

# multipart/form-data （傳送檔案是圖片或 PDF 時用這種請求）
如果我們提交的檔案為 「圖片、影片」 等，就必須使用這種 Content-Type。上傳檔案的操作需要使用 <input type="file"> 這個 HTML 標籤進行，並且需要將資料轉成 formData 格式才能順利 POST 給伺服器。

(這是比較進階的 POST 用法，同學可以先知道有這回事就好，有興趣的同學可以參考 [這篇文章](https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData) )

# text/plain （傳送記事本類型檔案）

**所以要做 API 請求時要先知道伺服器可以接受哪種請求方式，才不會出錯！**




# 使用 axios 實作表單註冊功能

[使用 axios 實作表單註冊登入功能程式範例](https://codepen.io/hong-wei/pen/MWJyemB?editors=1010)

# 使用 JS 原生程式 XMLhttp 的方式撰寫註冊登入功能
[JS 原生程式 XMLhttp 的方式撰寫註冊登入功能程式範例](https://codepen.io/hong-wei/pen/JjGEQWL?editors=0010)









# 凍結物件 freeze()
如果有物件或陣列裡面的屬性不要被改變、增加、刪除都可以用 freeze()
相關 [知識參考連結](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)

# [BMI 計算機](https://codepen.io/hong-wei/pen/xxZpPgM?editors=0010)
# [高雄旅遊網](https://codepen.io/hong-wei/pen/eYJGaPr)