# Javascript 第三章 運算元和運算子
###### tags: `JS X Codeshiba`
## 運算式(Expression)和運算子(Operator)\
JS的語法可以分成兩種
1. 敘述句(Statement) **執行某個動作**
變數宣告、賦值或是if判斷式都是
可以當成一種指令,要求某個東西
```javascript=
var f;
```
2. 運算式(Expression) **產生一個值**
呼叫function的參數,或是在=的右側,都是屬於運算式的部分
明確地將某個東西轉換成產品
```javascript=
var f = 10*10*10;
```
## 解構運算式
```javascript=
let x;
x=3*5;
```
第一行是宣告陳述式,宣告變數x
第二行是兩個算數式的結合
1. 乘法運算式: 3*5(常值運算式)
2. 賦值運算式: x=15(識別碼運算式)
## 甚麼是運算子
運算子,類似運算式中的 **「動詞」**
## 運算子的分類
1. 算數運算子(Arithmetic Operator)
2. 指派運算子(Assignment Operator)
3. 位元運算子(Bitwise Operator)
4. 比較運算子(Comparison Operator)
5. 邏輯運算子(Logical Operator)
6. 字串運算子(String Operator)
7. 特殊運算子(Special Operator)
## 算數運算子
1. ++x 預先遞增,表示把x遞增1,接著用新值計算
2. x++ 延後遞增,表示把x遞增1,接著用原先的x來計算
下列的呈現方式都是a=a+1的撰寫方法,不過呈現出來的效果不一樣
a++ 會呈現的是原始的數值
++a 會呈現的是+1後的數值
### 算是運算子的特性
1. Infinity
當兩個Infinity相減時(或是加上-Infinity),會產生NaN

2. '+'號的使用
自動轉型的特性,讓數字可以和字串相加
如果要規避數字被判斷成字串,可以使用()來處理

`+`為運算子(或稱運算符)
`數字`為運算元

運算元和運算子可以拿來撰寫條件

### 餘數

### 預設值
透過 `||=` 來給予變數預設值
若本身已經被賦予值,則會以原有的值為主

## 比較運算子
### == 和 === 的比較
如果是要嚴謹的比較,使用`===`,因為這個不會做「自動轉型」
如果比較包含轉換後的型別,則可以使用`==`,但基於上述原因,還是鼓勵使用===

建議可以把字串轉換成數字,改用嚴格相等運算子來比較
### !=和!==的比較
不等於的意思~~
`!=` 也會把型別自動轉換
`!==` 則不會,所以如果要互相比較,還是使用!==比較好
### 怎麼對數字進行相等(identity)或一致(equality)的比較
```javascript=
let n = 0;
while(true) {
n += 0.1;
if(n === 0.3) break;
}
console.log(`stopped at ${n}`);
```
上述例子無法跳出迴圈,因為數字的特性(都是double),所以無法跳出迴圈,此時可以透過`Number.EPSILON`來改寫迴圈
```javascript=
let n = 0;
while(true) {
n += 0.1;
if(Math.abs(n-0.3)<Number.EPSILON) break;
}
console.log(`stopped at ${n}`);
```
### 字串串接的特性
如果使用+號,把200(數字)加上'123'(字串),數字將會自動轉換為字串
如果使用-號,把200(數字)扣掉'123'(字串),文字將會自動轉換為數字
如下所示

```javascript=
3+5+"8" //字串88
"3"+5+8 //計算成字串358
```
## 邏輯運算子
JS把下列值分為truthy和falsy值
### truthy
1. 所有物件(包含使用valueOf()方法時,會回傳false的物件)
2. 所有陣列(甚至包括空的陣列)
3. 裡面只有空白的字串(例如" ")
4. 字串"false"
### falsy
1. undefined
2. null
3. false
4. 0
5. NaN
6. ''(空字串)
### And(&&) Or(||)

AND只會在兩個運算元都是true才會是true
OR只會在兩個運算元都是false才會是false
### 短路計算(short-circuit evaluation)
and 和 or 也可以透過運算式來比較
值得一提的是,如果只可以透過前面的部分就判定True或False
則電腦只會跑到前面判定的部分為止
例如下方的&&和||跑出來的結果就有所差異

### Not(!)

### 條件運算子(三源運算子)
```javascript=
const doIt = false;
const result = doIt ? "Did it!" : "Didn't do it.";
//如果doIt是truthy, 則計算Did it
//如果doIt是falsy, 則計算Didn't do it
```
### 逗號運算子
當你想要執行多個運算式,但只關心最後一個運算式的結果時,可以透過以下的範例進行
因為逗號運算子的優先順序偏低,所以我們如果不放在括號內,只會回傳第一個值(x=0)
```javascript=
let x = 0, y = 10, z;
z = (x++, y++); //z=10;
z = x++, y++; //z=0;
```
## 分組運算子
使用括號,可以修改或明確標示運算子的優先順序
### typeof運算子
哀,這個運算子無法完全對應JS七種資料型態,所以容易被混淆
| 運算式 | 回傳值 | Memo |
|-------|:-----:|------:|
| typeof undefined | "undefined" | |
| typeof null | "object" | |
| typeof {} | "object" | 特別注意 |
| typeof true | "boolean" | |
| typeof 1 | "number" | |
| typeof "" | "string" | |
| typeof Symbol() | "symbol" | |
| typeof function(){} | "function" | |
| typeof [] | "object" | 特別注意 |
### Void運算子
強制執行運算式求值,再回傳undefined
在HTML標籤內的URL可以看得到
```htmlembedded=
<a href="javascript:void 0">Do nothing.</a>
```
### 賦值運算子
指派一個值給一個變數,在等號左邊的東西是**變數**、**特性**或是**陣列元素**,必須是某種可以保存值的東西
賦值本身是個運算式,所以被回傳的值,就是要指派的值,所以可以把賦值式串起來,在其他運算式中進行賦值
```javascript=
let v, v0;
v=v0=9.8; //串接賦值,v0會先得到9.8
//接著v值得到9.8
```
```javascript=
const nums = [3,5,15,7,5];
let n, i=0;
while((n=nums[i])<10, i++ < nums.length){
console.log(`Number less than 10: ${n}.`);
}
console.log(`Number greater than 10 found: ${n}.`);
console.log(`${nums.length} numbers remain.`);
```
## 解構賦值
ES6內部的功能,可以將一個物件或陣列解構成各個變數
```javascript=
//一般物件
const obj = {b:2, c:3, d:4};
```
```javascript=
//物件解構賦值
const {a, b, c} = obj;
a; // undefined
b; // 2
c; // 3
d; // 參考錯誤,未定義"d"
```
解構物件時,變數名稱必須符合物件中的特性名稱
陣列解構只能指派**識別碼**特性名稱
```javascript=
//我們可以在同一個陳述式中進行宣告與賦值,並在賦值時做物件解構
const obj = {b:2, c:3, d:4};
let a, b, c;
{a,b,c} = obj; //這個會產生錯誤
({a,b,c}=obj); //可以進行解構,但要用括號包起來
//{b: 2, c: 3, d: 4}
```
使用陣列解構,可以指派任何我想要的名稱
```javascript=
const arr = [1, 2, 'z']
let [x , y] = arr;
console.log(x); //1
console.log(y); //2
console.log(f); //錯誤,f沒有被定義
```
```javascript=
const arr = [1, 2, 'z', 6, 7, 8]
let [x , y, ...rest] = arr; //使用擴張運算子(...)來把其餘元素放入新陣列
console.log(x); //1
console.log(y); //2
console.log(rest); //["z", 6, 7, 8]
```
## 樣板字串中的運算式
```javascript=
const roomTempC = 21.5;
let currentTempC = 19.5;
const message = `The current temperature is ` + `${currentTempC-roomTempC}\u00b0c different than room temperature.`;
const fahrenheit =
`The current temperature is ${currentTempC*9/5+32}\u00b0F`;
//The current temperature is -2°c different than room temperature.
//The current temperature is 67.1°F
```
## 運算式與控制流程模式
### 把if...else轉成條件運算式
原有的控制流程:
```javascript=
if(isPrime(n)){
label = 'prime';
} else {
label = 'non-prime';
}
```
可以轉換成:
```javascript=
label = isPrime(n)? 'prime' : 'non-prime';
```
### 把if陳述式轉換成短路邏輯OR運算式
```javascript=
if(!options)options = {};
```
轉換成
```javascript=
options = options || {};
```