[TOC]
>>[info] 操作符按使用方法可以分為:一元操作符、位操作符、布爾操作符、乘性操作符、加性操作符、關系操作符、相等操作符、條件操作符、賦值操作符、逗號操作符這10種操作符。ECMAScript 操作符的與眾不同之處在于,它們能夠適用于很多值,例如字符串、數字值、布爾值,甚至對象。不過,在應用于對象時,相應的操作符通常都會調用對象的 valueOf()和(或) toString()方法,以便取得可以操作的值。
## 一元操作符
只能操作一個值的操作符,叫**一元操作符**。一元運算符是ECMAScript中最簡單的操作符。
#### 1、遞增和遞減操作符
遞增遞減即`++`和`--`,而遞增和遞減又分為前置型(前`++`或前`--`)和后置型(后`++`或后`--`),前置型為先遞增或遞減,而后置型為下次使用時再進行遞增或遞減。
~~~
var age = 20;
alert(++age); // 21,前置型,這里相當于 age + 1
var age = 20;
alert(age--); // 20,后置型,先使用,后遞減,所以這里得到的值依然是20
alert(age); // 19,此時再使用到此變量時,會進行前面的遞減操作,所以得到的是 19
var age = 20;
var newAge = --age + 2;
alert(age); // 19,因為 age 在上一行被執行了前置遞減操作,所以目前的 age 的值為 19
alert(newAge); // 21,因為 --age 為前置遞減,所以先遞減后運算,此時 age 的值為18,再 + 2,所以值為 21
var num1 = 20;
var num2 = 2;
var num3 = --num2 + num1; // 21,先執行前num2的前置--操作,此時num2的值為 1,所以 1 + 20 = 21
var num4 = num2 + num1; // 21,此時經過上面的前置遞減操作,num2的值已經變為 1,所以此處的num4的值應該為 21
var num1 = 20;
var num2 = 2;
var num3 = num2++ + num1; // 22,num2++為后置遞加,所以此時不會進行遞加運算, 2 + 20 = 22
var num4 = num2 + num1; // 23,此時經過上面的后置遞加操作,num2的值已經變為 3,所以此處的num4的值應該為 23
~~~
>[danger] 遞增遞減操作在用在其它數據類型中,會先將其轉換為數值型,再進行遞增或遞減操作,如果不能轉換為數字,則會轉換為`NaN`,在應用到對象中時,會先調用對象中的`valueOf()`方法,取得一個可共操作的值,然后再對該值進行操作,如果結果是`NaN`,則再調用`toStrong()`方法后,再進行操作
#### 2、一元加和減操作符
一元加操作符是在需要操作的數值前面放一個加號(+),對數值不會產生任何影響,對于非數值,會自動轉換為數值,如果轉不了數值型,則會被轉換為`NaN`。
一元減操作符主要用于表示負數,例如將正數轉換為負數。
~~~
var age = 20;
var newAge = +age; //仍然是 20,不會變
var num1 = 20;
var num2 = -num1; // -20,會被轉換為負數
~~~
## 位作符
位操作符用于在最基本的層次上,即按內存中表示數值的位來操作數值。 ECMAScript 中的所有數值都以 IEEE-754 64 位格式存儲,但位操作符并不直接操作 64 位的值。而是先將 64 位的值轉換成 32 位的整數,然后執行操作,最后再將結果轉換回 64 位。對于開發人員來說,由于 64 位存儲格式是透明的,因此整個過程就像是只存在 32 位的整數一樣。
對于有符號的整數, 32 位中的前 31 位用于表示整數的值。第 32 位用于表示數值的符號: 0 表示正數, 1 表示負數。這個表示符號的位叫做**符號位**,符號位的值決定了其他位數值的格式。其中,正數以純二進制格式存儲, 31 位中的每一位都表示 2 的冪。第一位(叫做位 0)表示 2<sup>0</sup>,第二位表示 2<sup>1</sup>,以此類 推 。 沒 有 用 到 的 位 以 0 填 充 , 即 忽 略 不 計 。 例 如 , 數 值 18 的 二 進 制 表 示 是 `00000000000000000000000000010010`,或者更簡潔的`10010`。這是 5 個有效位,這 5 位本身就決定了實際的值,如下圖所示:
:-: 
負數同樣以二進制碼存儲,但使用的格式是二進制補碼。計算一個數值的二進制補碼,需要經過下列 3 個步驟:
1. 求這個數值絕對值的二進制碼(例如,要求`-18`的二進制補碼,先求`18`的二進制碼);
2. 求二進制反碼,即將`0`替換為 `1`,將`1`替換為`0`;
3. 得到的二進制反碼加 1。
~~~
// 要根據這 3 個步驟求得`-18`的二進制碼,首先就要求得`18`的二進制碼,即:
0000 0000 0000 0000 0000 0000 0001 0010
// 然后,求其二進制反碼,即 0 和 1 互換:
1111 1111 1111 1111 1111 1111 1110 1101
// 最后,二進制反碼加 1:
1111 1111 1111 1111 1111 1111 1110 1101
1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 1110 // -18 的結果
~~~
要注意的是,在處理有符號整數時,是不能訪問位 31 的。
#### 1、按位非(NOT)
按位非操作符由一個波浪線(~)表示,執行按位非的結果就是返回數值的反碼。按位非是ECMAScript 操作符中少數幾個與二進制計算有關的操作符之一。
~~~
var num1 = 25; // 二進制 00000000000000000000000000011001
var num2 = ~num1; // 二進制 11111111111111111111111111100110
alert(num2); // -26
~~~
#### 2、按位與(AND)
按位與操作符由一個和號字符(&)表示,它有兩個操作符數。從本質上講,按位與操作就是將兩個數值的每一位對齊,然后根據下表中的規則,對相同位置上的兩個數執行 AND 操作:
~~~
第一個數的值 第二個數的值 結果
1 1 1
1 0 0
0 1 0
0 0 0
~~~
也就是說,按位與操作只在兩個數值對應的對應位都是1時才返回1,否則返回的結果都是0。
#### 3、按位或(OR)
按位或操作符由一個豎線符號(|)表示,同樣也有兩個操作數。按位或操作遵循下面這個真值表。
~~~
第一個數的值 第二個數的值 結果
1 1 1
1 0 1
0 1 1
0 0 0
~~~
按位或中,兩個數值對應位任何一個為`1`的時候,都返回`1`,只有兩個都為`0`的時候,才返回`0`。
#### 4、按位異或(XOR)
按位異或操作符由一個插入符號(^)表示,也有兩個操作數。以下是按位異或的真值表。
~~~
第一個數的值 第二個數的值 結果
1 1 0
1 0 1
0 1 1
0 0 0
~~~
按位異或與按位或的不同之處在于,這個操作在兩個數值對應位上只有一個 `1` 時才返回 `1`,如果對應的兩位都是 `1` 或都是 `0`,則返回 `0`。
#### 5、左移
左移操作符是由兩個小于號(<<)組成,這個操作符會將數值的所有位向左移動指定的位數。例如將`2`(二進制碼為`10`)向左移動5位,結果就是`64`(二進制碼為1000000),向左側移動后,多出的空位將用`0`來填充。左移不會影響被操作數的符號位。
~~~
var oldValue = 2; // 等于二進制的 10
var newValue = oldValue << 5; // 等于二進制的 1000000,十進制的 64
~~~
#### 6、有符號的右移
有符號的右移操作符由兩個大于號(>>)表示,這個操作符會將數值向右移動,但保留符號位(即正負號標記)。有符號的右移操作與左移操作恰好相反,即如果將 64 向右移動 5 位,結果將變回 2:
~~~
var oldValue = 64; // 等于二進制的 1000000
var newValue = oldValue >> 5; // 等于二進制的 10 ,即十進制的 2
~~~
#### 7、無符號的右移
無符號右移操作符由 3 個大于號(>>>)表示,這個操作符會將數值的所有 32 位都向右移動。對正數來說,無符號右移的結果與有符號右移相同。但是對負數來說,情況就不一樣了。首先,無符號右移是以 0 來填充空位,而不是像有符號右移那樣以符號位的值來填充空位。
~~~
var oldValue = 64; // 等于二進制的 1000000
var newValue = oldValue >>> 5; // 等于二進制的 10 ,即十進制的 2
var oldValue = -64; // 等于二進制的 11111111111111111111111111000000
var newValue = oldValue >>> 5; // 00000111111111111111111111111110 等于十進制的 134217726
~~~
## 布爾操作符
布爾操作符一共有 3 個:非(NOT)、與(AND)和或(OR)
#### 1、邏輯非
邏輯非操作符由一個嘆號(!)表示,可以應用于 ECMAScript 中的任何值。無論這個值是什么數據類型,這個操作符都會返回一個布爾值。邏輯非操作符首先會將它的操作數轉換為一個布爾值,然后再對其求反。
* 對象(包含空對象) ,返回 false
* 空字符串,返回 true
* 非空字符串,返回 false
* 數值0,返回 true
* 非 0 數值(包含 Infinity),返回 false
* null,返回 true
* NaN,返回 true
* undefined 返回 true
~~~
var obj = {};
alert(!obj); // false
alert(!false); // true
alert(!"false") // false
alert(!0); // true
alert(!""); // true
alert(!20); // false
~~~
#### 2、邏輯與(&&)
邏輯與操作符由兩個和號(&&)表示,有左右兩個操作數,如下面的例子所示:
~~~
var result = var1 && var2;
~~~
邏輯與操作符,操作符兩邊的操作數都為 `true` 的情況下,才返回 `true`,否則都會返回 `false`。
~~~
第一個操作數 第二個操作數 結果
true true true
true false false
false true false
false false false
~~~
邏輯與操作可以應用于任何數據類型,但如果邏輯與操作符兩邊有一個操作數不是布爾值時,邏輯與操作就不一定會返回布爾值,此時,遵循以下規則
* 如果第一個操作數為對象,則返回第二個操作數
* 如果第二個操作數為對象,則只有在第一個操作數的結果為 true 的情況下,才會返回該對象,否則返回第一個操作數
* 如果兩個操作數都為對象,則返回第二個操作數
* 如果第一個操作數為數值 0,則直接返回 0
* 如果第一個操作數為 false,則直接返回 false
* 如果兩個操作數中,出現 null,則直接返回 null
* 如果兩個操作數中,出現了NaN,則直接返回 NaN
* 如果兩個操作數據中,出現了 undefined,則直接返回 undefined
邏輯與操作屬于短路操作,也就是說,只要第一個操作值為 false 的情況下,就不會去執行第二個操作值,而直接返回 false
#### 3、 邏輯或(||)
邏輯或操作符由兩個豎線符號(||)表示,也有左右兩個操作數,邏輯或中,兩邊的操作數,只要有一個為 `true`,就返回 `true`,也就是說,只有兩個操作數都為 `false` 的情況下,才返回 `false`。
與邏輯與操作相似,如果有一個操作數不是布爾值,邏輯或也不一定返回布爾值;此時,它遵循下列規則:
* 如果第一個操作數是對象,則返回第一個操作數;
* 如果第一個操作數的求值結果為 false,則返回第二個操作數;
* 如果兩個操作數都是對象,則返回第一個操作數;
* 如果兩個操作數都是 null,則返回 null;
* 如果兩個操作數都是 NaN,則返回 NaN;
* 如果兩個操作數都是 undefined,則返回 undefined。
與邏輯與操作符相似,邏輯或操作符也是短路操作符。也就是說,如果第一個操作數的求值結果為`true`,就不會對第二個操作數求值了。
## 乘性操作符
ECMAScript 定義了 3 個乘性操作符:乘法、除法和求模(取余)。如果參與乘性計算的某個操作數不是數值,后臺會先使用 `Number()`轉型函數將其轉換為數值。也就是說,空字符串將被當作`0`,布爾值 `true` 將被當作 `1`。
#### 1、乘法
乘法操作符是由一個星號(\*)表示,用來計算兩個數的乘積。
~~~
var result = 20 * 18; // 等于 360
~~~
在處理特殊值的情況下,乘法操作符遵循下列特殊的規則:
* 如果操作數都是數值,執行常規的乘法計算,即兩個正數或兩個負數相乘的結果還是正數,而如果只有一個操作數有符號,那么結果就是負數。如果乘積超過了 ECMAScript 數值的表示范圍,則返回 Infinity 或-Infinity;
* 如果有一個操作數是 NaN,則結果是 NaN;
* 如果是 Infinity 與 0 相乘,則結果是 NaN;
* 如果是 Infinity 與非 0 數值相乘,則結果是 Infinity 或-Infinity,取決于有符號操作數的符號;
* 如果是 Infinity 與 Infinity 相乘,則結果是 Infinity;
* 如果有一個操作數不是數值,則在后臺調用 Number()將其轉換為數值,然后再應用上面的規則。
#### 2、除法
除法操作符由一個斜線(/)表示,執行第二個操作數第第一個操作數的計算。
~~~
var result = 10 / 5; //等于 2
~~~
#### 3、求模(取余)
求模(取余)操作符由一個百分號(%)表示。
~~~
var result = 9 % 2; // 等于 1
~~~
## 加性操作符
加性操作符包括常用的加法和減法
#### 1、加法(+)
~~~
var result = 10 + 5; // 等于 15
~~~
如果加法操作符兩邊都是數值,則執行常規加法運算,然后返回相應的結果。但如果為其它類型的值,則遵循以下規則:
* 如果有一個操作數是`NaN`,則結果是`NaN`;
* 如果是`Infinity` 加 `Infinity`,則結果是 `Infinity`;
* 如果是`-Infinity` 加`-Infinity`,則結果是`-Infinity`;
* 如果是 `Infinity` 加`-Infinity`,則結果是 `NaN`;
* 如果是`+0` 加`+0`,則結果是`+0`;
* 如果是`-0` 加`-0`,則結果是`-0`;
* 如果是`+0` 加`-0`,則結果是`+0`。
不過,如果有一個操作數是字符串,那么就要應用如下規則:
* 如果兩個操作數都是字符串,則將第二個操作數與第一個操作數拼接起來;
* 如果只有一個操作數是字符串,則將另一個操作數轉換為字符串,然后再將兩個字符串拼接起來。
* 如果有一個操作數是對象、數值或布爾值,則調用它們的 `toString()`方法取得相應的字符串值,然后再應用前面關于字符串的規則。對于 `undefined` 和 `null`,則分別調用 `String()`函數并取得字符串`"undefined"`和`"null"`。
~~~
var result = 20 + 20; // 40 兩個操作值都為數值的情況下,直接進行相加運算
var result = 20 + "20"; // "2020",有一個操作值為字符串的情況下,直接進行字符串拼接
~~~
#### 2、減法(-)
~~~
var result = 10 - 6; // 等于 4
~~~
與加法類似,如果兩個操作數都為數值的情況下,直接進行減法運算后,返回運算結果,如果操作數為其它類型,則會進行轉換。
~~~
var result = 5 - 4; // 1,正常數值運算
var result = 5 - NaN; // NaN,如果有一個操作數為 NaN,則返回NaN
var result = Infinity - Infinity; // NaN
var result = -Infinity - -Infinity; // NaN
var result = Infinity - -Infinity; // Infinity
var result = -Infinity - Infinity; // -Infinity
var result = 0 - 0; // 0
var result = 0 - -0; // -0
var result = -0 - -0; // 0
var result = 20 - true; // 19,true 被轉換為了 1
var result = 20 - ""; // 20,"" 被轉換為了 0
var result = 20 - "2"' // 18,"2" 被轉換為了 2
var result = 20 - null; // 20,null 被轉換為了 0
~~~
>[danger] 如果有一個操作數是字符串、布爾值、 `nul`l 或 `undefined`,則先在后臺調用 `Number()`函數將其轉換為數值,然后再根據前面的規則執行減法計算。如果轉換的結果是 `NaN`,則減法的結果就是 `NaN`;
>如果有一個操作數是對象,則調用對象的 `valueOf()`方法以取得表示該對象的數值。如果得到的值是 NaN,則減法的結果就是 `NaN`。如果對象沒有 `valueOf()`方法,則調用其 `toString()`方法并將得到的字符串轉換為數值。
## 關系操作符
關系操作符包含:大于(>),小于(<)、大于等于(>=),小于等于(<=),這幾個操作符都返回為布爾值,成立則返回 `true`,否則返回 `false`。
如果兩個操作數都是數值型,則直接進行比較,如果兩個都為英文字符串,則比較其對應的字符串編碼值。否則會將其轉換為數值型再進行比較。
~~~
var result = 5 > 3; // true
var result = 5 < 3; // false
var result = "red" > "blue"; // true,會比較其它字符編碼
var result = "23" < "3"; // true,因為在兩個字符串進行比較時,會直接比較其字符編碼,而不會進行轉換
~~~
## 相等操作符
#### 1、相等和不相等(== 和 !=)
ECMAScript中,相等操作符是由兩個等號(==)表示,如果兩個操作數相等,則返回`true`,否則返回`false`。
不相等用嘆號和等號(!=)表示,與相等(==)剛好相反,兩個操作數不相等的情況下,返回`true`,否則返回`false`。在進行相等和不相等時,會自動轉換為相同的數據類型再進行比較。
~~~
alert(1 == true); // true,true 會自動轉換為 1
alert(5 == "5"); // true,"5" 會自動轉換為 5
alert(null == undefined); // true
alert(NaN == NaN); // false,NaN不與任何值相等,包括它自己
alert(NaN != NaN); // true
alert(undefined == 0); // false
~~~
#### 2、全等和不全等(=== 和 !==)
全等是由三個等號(===)表示,全等不會進行數據轉換而直接進行比較,相同返回 `true`,否則返回 `false`。
不全等剛好和全等相反,兩邊不全等時返回 `true`,兩邊全等則返回 `false`。
~~~
var result = 20 == "20"; // true,會將 "20"轉換為 20
var result = 20 === "20"; // false,不會進行轉換,直接比較
var result = 20 != "20"; // false
var result = 20 !=="20"; // true
~~~
## 條件操作符(三元運算符)
條件運算符也叫三元運算符。三元運算符是各種編程語言中非常常用的一種運算符,一般用于比較或賦值當中,其語法格式為:
~~~
variable = boolean_expression ? true_value : false_value;
~~~
以上這行代碼表示,根據表達式`boolean_expression`的結果給 `variable`賦值,如果表達式 `boolean_expression`成立,則執行問號(?)后面、冒號(:)前面的代碼,否則執行冒號(:)后面的代碼,也就是說,如果表達式`boolean_expression`成立,則將`true_value`賦值給`variable`,否則將`false_value`賦值給`variable`。
~~~
var num1 = 5;
var num2 = 3;
var num3 = (num1 > num2) ? num1 : num2; // 3
(num1 > num2) ? num2++ : num1++; //如果num1 大于num2的話,那么給num2遞增,否則給num1遞增
alert(num2); // 4,
alert(num1); // 5
~~~
## 賦值操作符
賦值操作符是用一個等號(=)表示,是用來將右則的值賦給左側的變量。如果在等于號(=)前面再添加乘性操作符、加性操作符或位操作符,就可以完成復合賦值操作。
~~~
var age = 20; // 常規賦值操作
age += 1; // 相當于 age = age + 1;
alert(age); // 21
~~~
常見的復合賦值操作如下:
* 乘/賦值(*=)
* 除/賦值(/=)
* 模/賦值(%=)
* 加/賦值(+=)
* 減/賦值(?=)
* 左移/賦值(<<=)
* 有符號右移/賦值(>>=)
* 無符號右移/賦值(>>>=)
>[danger] 設計這些操作符的主要目的就是簡化賦值操作。使用它們不會帶來任何性能的提升
## 逗號操作符
使用逗號操作符可以在一條語句中執行多個操作,常用于賦值操作,一次給多個變量賦值。
~~~
var num1 = 1,
num2 = 2,
num3 = 3;
var num4,num5,num6 = 4,5,6;
~~~