# 算術運算符
運算符是處理數據的基本方法,用來從現有的值得到新的值。JavaScript 提供了多種運算符,覆蓋了所有主要的運算。
## 概述
JavaScript 共提供10個算術運算符,用來完成基本的算術運算。
- **加法運算符**:`x + y`
- **減法運算符**: `x - y`
- **乘法運算符**: `x * y`
- **除法運算符**:`x / y`
- **指數運算符**:`x ** y`
- **余數運算符**:`x % y`
- **自增運算符**:`++x` 或者 `x++`
- **自減運算符**:`--x` 或者 `x--`
- **數值運算符**: `+x`
- **負數值運算符**:`-x`
減法、乘法、除法運算法比較單純,就是執行相應的數學運算。下面介紹其他幾個算術運算符,重點是加法運算符。
## 加法運算符
### 基本規則
加法運算符(`+`)是最常見的運算符,用來求兩個數值的和。
```javascript
1 + 1 // 2
```
JavaScript 允許非數值的相加。
```javascript
true + true // 2
1 + true // 2
```
上面代碼中,第一行是兩個布爾值相加,第二行是數值與布爾值相加。這兩種情況,布爾值都會自動轉成數值,然后再相加。
比較特殊的是,如果是兩個字符串相加,這時加法運算符會變成連接運算符,返回一個新的字符串,將兩個原字符串連接在一起。
```javascript
'a' + 'bc' // "abc"
```
如果一個運算子是字符串,另一個運算子是非字符串,這時非字符串會轉成字符串,再連接在一起。
```javascript
1 + 'a' // "1a"
false + 'a' // "falsea"
```
加法運算符是在運行時決定,到底是執行相加,還是執行連接。也就是說,運算子的不同,導致了不同的語法行為,這種現象稱為“重載”(overload)。由于加法運算符存在重載,可能執行兩種運算,使用的時候必須很小心。
```javascript
'3' + 4 + 5 // "345"
3 + 4 + '5' // "75"
```
上面代碼中,由于從左到右的運算次序,字符串的位置不同會導致不同的結果。
除了加法運算符,其他算術運算符(比如減法、除法和乘法)都不會發生重載。它們的規則是:所有運算子一律轉為數值,再進行相應的數學運算。
```javascript
1 - '2' // -1
1 * '2' // 2
1 / '2' // 0.5
```
上面代碼中,減法、除法和乘法運算符,都是將字符串自動轉為數值,然后再運算。
### 對象的相加
如果運算子是對象,必須先轉成原始類型的值,然后再相加。
```javascript
var obj = { p: 1 };
obj + 2 // "[object Object]2"
```
上面代碼中,對象`obj`轉成原始類型的值是`[object Object]`,再加`2`就得到了上面的結果。
對象轉成原始類型的值,規則如下。
首先,自動調用對象的`valueOf`方法。
```javascript
var obj = { p: 1 };
obj.valueOf() // { p: 1 }
```
一般來說,對象的`valueOf`方法總是返回對象自身,這時再自動調用對象的`toString`方法,將其轉為字符串。
```javascript
var obj = { p: 1 };
obj.valueOf().toString() // "[object Object]"
```
對象的`toString`方法默認返回`[object Object]`,所以就得到了最前面那個例子的結果。
知道了這個規則以后,就可以自己定義`valueOf`方法或`toString`方法,得到想要的結果。
```javascript
var obj = {
valueOf: function () {
return 1;
}
};
obj + 2 // 3
```
上面代碼中,我們定義`obj`對象的`valueOf`方法返回`1`,于是`obj + 2`就得到了`3`。這個例子中,由于`valueOf`方法直接返回一個原始類型的值,所以不再調用`toString`方法。
下面是自定義`toString`方法的例子。
```javascript
var obj = {
toString: function () {
return 'hello';
}
};
obj + 2 // "hello2"
```
上面代碼中,對象`obj`的`toString`方法返回字符串`hello`。前面說過,只要有一個運算子是字符串,加法運算符就變成連接運算符,返回連接后的字符串。
這里有一個特例,如果運算子是一個`Date`對象的實例,那么會優先執行`toString`方法。
```javascript
var obj = new Date();
obj.valueOf = function () { return 1 };
obj.toString = function () { return 'hello' };
obj + 2 // "hello2"
```
上面代碼中,對象`obj`是一個`Date`對象的實例,并且自定義了`valueOf`方法和`toString`方法,結果`toString`方法優先執行。
## 余數運算符
余數運算符(`%`)返回前一個運算子被后一個運算子除,所得的余數。
```javascript
12 % 5 // 2
```
需要注意的是,運算結果的正負號由第一個運算子的正負號決定。
```javascript
-1 % 2 // -1
1 % -2 // 1
```
所以,為了得到負數的正確余數值,可以先使用絕對值函數。
```javascript
// 錯誤的寫法
function isOdd(n) {
return n % 2 === 1;
}
isOdd(-5) // false
isOdd(-4) // false
// 正確的寫法
function isOdd(n) {
return Math.abs(n % 2) === 1;
}
isOdd(-5) // true
isOdd(-4) // false
```
余數運算符還可以用于浮點數的運算。但是,由于浮點數不是精確的值,無法得到完全準確的結果。
```javascript
6.5 % 2.1
// 0.19999999999999973
```
## 自增和自減運算符
自增和自減運算符,是一元運算符,只需要一個運算子。它們的作用是將運算子首先轉為數值,然后加上1或者減去1。它們會修改原始變量。
```javascript
var x = 1;
++x // 2
x // 2
--x // 1
x // 1
```
上面代碼的變量`x`自增后,返回`2`,再進行自減,返回`1`。這兩種情況都會使得,原始變量`x`的值發生改變。
運算之后,變量的值發生變化,這種效應叫做運算的副作用(side effect)。自增和自減運算符是僅有的兩個具有副作用的運算符,其他運算符都不會改變變量的值。
自增和自減運算符有一個需要注意的地方,就是放在變量之后,會先返回變量操作前的值,再進行自增/自減操作;放在變量之前,會先進行自增/自減操作,再返回變量操作后的值。
```javascript
var x = 1;
var y = 1;
x++ // 1
++y // 2
```
上面代碼中,`x`是先返回當前值,然后自增,所以得到`1`;`y`是先自增,然后返回新的值,所以得到`2`。
## 數值運算符,負數值運算符
數值運算符(`+`)同樣使用加號,但它是一元運算符(只需要一個操作數),而加法運算符是二元運算符(需要兩個操作數)。
數值運算符的作用在于可以將任何值轉為數值(與`Number`函數的作用相同)。
```javascript
+true // 1
+[] // 0
+{} // NaN
```
上面代碼表示,非數值經過數值運算符以后,都變成了數值(最后一行`NaN`也是數值)。具體的類型轉換規則,參見《數據類型轉換》一章。
負數值運算符(`-`),也同樣具有將一個值轉為數值的功能,只不過得到的值正負相反。連用兩個負數值運算符,等同于數值運算符。
```javascript
var x = 1;
-x // -1
-(-x) // 1
```
上面代碼最后一行的圓括號不可少,否則會變成自減運算符。
數值運算符號和負數值運算符,都會返回一個新的值,而不會改變原始變量的值。
## 指數運算符
指數運算符(`**`)完成指數運算,前一個運算子是底數,后一個運算子是指數。
```javascript
2 ** 4 // 16
```
注意,指數運算符是右結合,而不是左結合。即多個指數運算符連用時,先進行最右邊的計算。
```javascript
// 相當于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512
```
上面代碼中,由于指數運算符是右結合,所以先計算第二個指數運算符,而不是第一個。
## 賦值運算符
賦值運算符(Assignment Operators)用于給變量賦值。
最常見的賦值運算符,當然就是等號(`=`)。
```javascript
// 將 1 賦值給變量 x
var x = 1;
// 將變量 y 的值賦值給變量 x
var x = y;
```
賦值運算符還可以與其他運算符結合,形成變體。下面是與算術運算符的結合。
```javascript
// 等同于 x = x + y
x += y
// 等同于 x = x - y
x -= y
// 等同于 x = x * y
x *= y
// 等同于 x = x / y
x /= y
// 等同于 x = x % y
x %= y
// 等同于 x = x ** y
x **= y
```
下面是與位運算符的結合(關于位運算符,請見后文的介紹)。
```javascript
// 等同于 x = x >> y
x >>= y
// 等同于 x = x << y
x <<= y
// 等同于 x = x >>> y
x >>>= y
// 等同于 x = x & y
x &= y
// 等同于 x = x | y
x |= y
// 等同于 x = x ^ y
x ^= y
```
這些復合的賦值運算符,都是先進行指定運算,然后將得到值返回給左邊的變量。
- 前言
- 入門篇
- 導論
- 歷史
- 基本語法
- 數據類型
- 概述
- null,undefined 和布爾值
- 數值
- 字符串
- 對象
- 函數
- 數組
- 運算符
- 算術運算符
- 比較運算符
- 布爾運算符
- 二進制位運算符
- 其他運算符,運算順序
- 語法專題
- 數據類型的轉換
- 錯誤處理機制
- 編程風格
- console 對象與控制臺
- 標準庫
- Object 對象
- 屬性描述對象
- Array 對象
- 包裝對象
- Boolean 對象
- Number 對象
- String 對象
- Math 對象
- Date 對象
- RegExp 對象
- JSON 對象
- 面向對象編程
- 實例對象與 new 命令
- this 關鍵字
- 對象的繼承
- Object 對象的相關方法
- 嚴格模式
- 異步操作
- 概述
- 定時器
- Promise 對象
- DOM
- 概述
- Node 接口
- NodeList 接口,HTMLCollection 接口
- ParentNode 接口,ChildNode 接口
- Document 節點
- Element 節點
- 屬性的操作
- Text 節點和 DocumentFragment 節點
- CSS 操作
- Mutation Observer API
- 事件
- EventTarget 接口
- 事件模型
- Event 對象
- 鼠標事件
- 鍵盤事件
- 進度事件
- 表單事件
- 觸摸事件
- 拖拉事件
- 其他常見事件
- GlobalEventHandlers 接口
- 瀏覽器模型
- 瀏覽器模型概述
- window 對象
- Navigator 對象,Screen 對象
- Cookie
- XMLHttpRequest 對象
- 同源限制
- CORS 通信
- Storage 接口
- History 對象
- Location 對象,URL 對象,URLSearchParams 對象
- ArrayBuffer 對象,Blob 對象
- File 對象,FileList 對象,FileReader 對象
- 表單,FormData 對象
- IndexedDB API
- Web Worker
- 附錄:網頁元素接口
- a
- img
- form
- input
- button
- option
- video,audio