---
# System prepended metadata

title: Javascript 第三章 運算元和運算子
tags: [JS X Codeshiba]

---

# 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
    ![](https://i.imgur.com/5jUgRIq.png)

2. '+'號的使用
    自動轉型的特性，讓數字可以和字串相加
    如果要規避數字被判斷成字串，可以使用()來處理
    ![](https://i.imgur.com/2PPe5vt.png)


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

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

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

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


### 餘數
![](https://i.imgur.com/phiK5sq.png)



### 預設值
透過 `｜|=` 來給予變數預設值
若本身已經被賦予值，則會以原有的值為主
![](https://i.imgur.com/YmnbNIA.png)

## 比較運算子

### == 和 === 的比較

如果是要嚴謹的比較，使用`===`，因為這個不會做「自動轉型」
如果比較包含轉換後的型別，則可以使用`==`，但基於上述原因，還是鼓勵使用===
![](https://i.imgur.com/u1S5P2r.png)

建議可以把字串轉換成數字，改用嚴格相等運算子來比較

### !=和!==的比較
不等於的意思~~
`!=` 也會把型別自動轉換
`!==` 則不會，所以如果要互相比較，還是使用!==比較好

### 怎麼對數字進行相等(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'(字串)，文字將會自動轉換為數字
如下所示
![](https://i.imgur.com/kCFprkC.png)

```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(||)
![](https://i.imgur.com/WFBVRqX.png)

AND只會在兩個運算元都是true才會是true
OR只會在兩個運算元都是false才會是false

### 短路計算(short-circuit evaluation)
and 和 or 也可以透過運算式來比較
值得一提的是，如果只可以透過前面的部分就判定True或False
則電腦只會跑到前面判定的部分為止
例如下方的&&和||跑出來的結果就有所差異
![](https://i.imgur.com/bgseYAC.png)

### Not(!)
![](https://i.imgur.com/OkqVh9f.png)

### 條件運算子(三源運算子)
```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 || {};
```
