# Javascript程式語言
> 2020-08-16 上課筆記
## 基本資料型態
### 常數 
```
const i = 1.02e2 // 1.02 * 10^2
```
### 基本資料型態與分類(兩者差異在於「變數值存入變數的方式」)
| 分類 | 資料型別 | 說明 |
| -------- | -------- | -------- |
| 基本型 | number | 數值 |
| 基本型 | string | 字串 |
| 基本型 | boolean | 布林 |
| 基本型 | symbol | 符號 |
| 基本型 | null/undefined | 空/未定義 |
| 參考型 | array | 陣列(資料集合-可透過索引值存取標籤) |
| 參考型 | object | 物件(資料集合-可透過名稱存取標籤) |
| 參考型 | function | 函式(函數)-一連串處理(步驟)的集合 |
## 基本型
基本型態的變數可直接填入變數值
## 參考型
參考型態的變數則用以儲存參考值(用以儲存「值」的記憶體位置)。
### 陣列
```
n = [1, 2, 3]
n = ['a', 'b', 'c']
n = [1, 'a', 2, 'b']
console.log(n)
console.log(n[2])
```
### 物件
```
n = {a: 1, b: 2, c: 3, 123:5}
console.log('物件', n['b'])
console.log('物件', n['123'])
```
### 小數
```
f = 0.7
f *= 10
console.log((1*10 - f)/10)
```
> 注意:
> - Javascript是用二進制來計算數值,之後再轉換成十進制,因此會有誤差。
> - 引用Math或BigDecimal.js等等可以解決浮點數運算的問題。
### 變數定義
#### let與var的不同 
- let無法重複定義,但var可以。
- let指令能更詳細的控制變數的有效範圍。
### 樣板字串-嵌入變數 
格式:**${變數名稱}**
```
var age = 7
var des = `我今年${age}歲`
```
### 多行字串 
```
let test =
`今天天氣熱
明天天氣好`
console.log(test)
```
## 運算子
### 指派運算子
```
a = 5
console.log(a += 5) // a = a + 5
console.log(a -= 2) // a = a - 2 (a=10 -> a=8)
console.log(a *= 3) // a = a * 3 (a=8 -> a=24)
console.log(a /= 4) // a = a / 4 (a=24 -> a=6)
console.log(a %= 5) //a = a % 5 (a=6 -> a=1)
```
### 基本型態與參考型態經過指派後的差別
1. 基本型態會複製本值,因此指派後的修改不影響原來變數內容。
2. 參考型態為複製參考,因此指派後的修改會影響原來變數內容。
```
a = 'str';
console.log('基本型指派前:', a);
a1 = a;
a1 = 'rts';
console.log('基本型指派後:', a);
b = [1, 2, 'v'];
console.log('參考型指派後:', b);
b1 = b;
b1[2] = 99;
console.log('參考型指派後:', b);
```
結果:
```
基本型指派前: str
基本型指派後: str
參考型指派後: [ 1, 2, 'v' ]
參考型指派後: [ 1, 2, 99 ]
```
### 解構指派 
#### 陣列解構指派
例如將一個陣列元素分別指定給不同的變數,原本用法:
```
c = [1, 2, 3, 4, 5];
c1=c[0]
c2=c[1]
c3=c[2]
c4=c[3]
c5=c[4]
```
解構指派用法:
```
c = [1, 2, 3, 4, 5];
[c1, c2, c3, c4, c5] = c;
```
> 注意:要用中括號包住
更多範例:
```
d = [1, 2, 3, 4, 5];
let [d1, d2, d3, d4, d5] = d;
console.log(d1, d2, d3, d4, d5);
```
#### 透過「...」將放不下的元素以陣列方式指定
```
e = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
let [e1, e2, e3, e4, e5, ...other] = e;
console.log(e1, e2, e3, e4, e5, other);
```
#### 變數交換
```
c = 5;
d = 9;
// [temp = c
// c = d
// d = temp
[c, d] = [d, c];
console.log(c, d);
```
#### 物件解構指派
```
let aa, bb, cc;
let o1, o2, o3;
array1 = [1, 2, 3];
obj1 = {a:1, b:2, c:3};
[aa, bb, cc] = array1;
console.log(aa, bb, cc);
({o1, o2, o3} = obj1); //物件指派寫法
console.log(o1, o2, o3);
```
> 變數名稱必須與屬性名稱相同
#### 巢狀物件解構指派
```
c = {
x: 1,
y: 2,
z: 3,
child: {
x1: 4,
y1: 5,
z1: 6
}
};
let {x, y, z, child: {x1, y1, z1}} = c;
console.log(x, y, z, x1, y1, z1)
```
#### 設定別名
```
// 設定別名
c = {
a: 1,
b: 2,
c: 3
}
let {a:name, b:title, c:content} = c;
console.log('name=', name, 'title=', title, 'content=', content);
array1 = [1, 2, 3];
obj1 = {a:1, b:2, c:3};
let aa, bb, cc;
let o1, o2, o3;
[aa, bb, cc] = array1;
console.log(aa, bb, cc);
({a:o1, b:o2, c:o3} = obj1); //物件指派寫法
console.log(o1, o2, o3);
```
### 比較運算子
```
console.log(1 == '1');
console.log(1 === '1');
console.log(1 != '1');
console.log(1 !== '1');
a = 3;
b = 5;
if(a > b) {
console.log('a比b大');
}
else {
console.log('a比b小');
}
console.log('a比b' + (a > b ? '大':'小'));
```
### 捷徑運算
下列值皆為false:
- 空字串('')
- 數值0、Nan(Not a Number)
- null、undefine
> 執行順序:由左到右做比較
```
b = 0;
c = 3;
a = b && c;
console.log(a);
a = b || c;
console.log(a);
```
結果:
```
0
3
```
```
a1 = 'a';
a2 = 99;
a3 = false;
a4 = [0, 0]
a5 = {}
console.log(a1 && a2 || a3 && a4 && a5)
console.log(a2 && a5 || a4 && a5)
console.log(a5 || a2 && a3 && a4 && a5)
console.log(a4 || a2 || a3 || a5)
```
輸出結果:
```
99
{}
{}
[ 0, 0 ]
```
##### 練習
1. a, b為兩個字串,如果相同就顯示「相同」否則顯示「不同」。
### delete運算子
```
a = 4;
delete a;
console.log('a=', a); // 這裡會出現例外錯誤,因為a變數被刪除了
// 明確宣告的變數無法刪除(let或var)
var a9 = 9;
delete a9;
console.log('a9=', a9); // a9仍然存在
// 陣列索引刪除後,後面的會往前移,只是原來的元素存取時會出現undefined
a = [1, 2, 3];
delete a[1];
console.log(a[1]);
console.log(typeof a);
// 刪除屬性,物件本身不會被刪除
a = {a:1, b:2};
delete a.b;
console.log(a);
```
### typeof運算子
```
a = 9;
console.log(typeof a);
a = '9';
console.log(typeof a);
a = false;
console.log(typeof a);
a = [1,2,3];
console.log(typeof a);
a = 1.5;
console.log(typeof a);
```
輸出結果:
```
number
string
boolean
number
object
```
> 陣列跟物件都只回傳object
### 運算子優先順序
```
a = 7
console.log((3 + 5) * 6);
console.log(a);
z = a += 9;
console.log(z);
z += 9 + 8 * 2;
console.log(z);
```
> 如果無法確定運算子優先權,但想優先運算的話,可以使用小括號包圍,因為小括號優先權最高。
## 控制語法
程式結構一般分為三類:
1. 依照撰寫順序執行的「循序」。
2. 依照條件分岐的處理「選擇」。
3. 重複執行特定處理的「重複」。
### if
### switch
### for
### for...in
### for...of 
### bread/continue
### 一次跳出巢狀迴圈 - label
### 例外處理 - try...catch...finally
### 避免JavaScript錯誤與法 - Strict模式
### 非同步載入外部程式 - async/defer屬性
##### 將<script>標籤放在網頁最後面(例如: </body>前面)
```
'use strict';
```
| 分類 | 限制 |
| -------- | -------- |
| 變數 | 禁止省略var |
| 變數 | 禁止使用未來保留的關鍵字 |
| 變數 | 禁止參數、屬性名稱重複 |
| 變數 | 禁止undefined/null指派 |
| 指令 | 禁止使用with |
| 指令 | 禁止存取arguments.callee |
| 指令 | Eval指令宣告之變數 |
| 其他 | 函數內的this無法轉成全域物件(會變成undefined) |
| 其他 | 禁止「0-」的8進位常數值 |
##### 優點:
1. 避免JavaScript陷阱。
2. 執行速度比Strict快。
3. 可增加未來相容性。
4. 可更加了解JavaScript的禁止狀況。
##### 使用HTML5非同步與法
```
<script async src="app.js"></script>
```
> 以src屬性設定的程式會透過非同步方式載入,在載入結束之後才接著執行。
```
<script async defer src="app.js"></script>
```
> 整個頁面都下載及分析完成後才會執行程式。
## 函式
##### 何謂函式:
1. 一段事先準備好的特定功能程式碼區塊。
##### 函式功用:
1. 減少重複的程式碼。
2. 讓程式更簡潔更有架構。
3. 讓程式碼更容易閱讀。
##### 函式結構:
1. 含式名稱。
2. 程式碼區塊。
3. 參數。
4. 回傳值。
命名規則:
1. 第一個字元只能是英文大小寫、底線、$號
2. 第2個字元及之後可以是英文大小寫、數字、底線、$號。
3. Javascriot保留字不可作為函式名稱。
4. 命名方式為snake命名法,全小寫,以底線分隔單字。