在ECMAScript中,有非常豐富的運算子和操作符,在這篇文章中將按通常的分類來稍微整理一下,不過在整理之前,先說明一下:
1、雖然標題是運算子和操作符,然而在我看來並沒有多少嚴格區分的必要,在英文中,貌似也是用一個Operator來表示,所以在下文中我可能會混用。甚至,一些不屬於運算子和操作符範疇的,我也整理在這裡,只要我覺得必要。
2、對於運算子的優先順序,你無需一一牢記——我相信你知道最簡單的”先乘除,後加減”,至於其它的,如果你不確定,加上括弧好了。在ECMAScript中,優先順序相同的從左向右運算。
3、對於一些程式設計語言通用的運算子,比如常用算術運算子(+-*/),我只會簡單的列舉一下,不會展開,但是請注意,並不是說這些不重要,相反,這些通用運算子甚至處於一個非常基礎的地位,只是我覺得你應該早已經熟悉,沒必要在這裡花時間強調。
4、那麼,這裡重點關注什麼呢?就是一些在ECMAScript中比較特殊的操作符,或者我認為值得花時間強調的一些地方。
運算子與操作符
| 類別 |
操作符 |
描述 |
說明 |
| 一元操作符 |
++ |
自增1 |
1、自增(減)有前置和後置兩種類型,前置先自增(減)再參與其它運算,後置先參與其它運算再自增(減)。 2、在ES中,自增(減)不僅適用於整數,它們可以作用於任意值,對於不是Number類型的值,會先按前一篇文章中的規則隱式轉換為Number,然後再自增(減),此時變數類型也會變成Number類型。 |
| -- |
自減1 |
| + |
一元加 |
一元加最主要的應用就是將運算元轉變為Number類型,相當於調用Number()轉換。 |
| - |
一元減 |
一元減則是在一元加的基礎之上再取其相反數。 |
| 算術操作符 |
+ |
加 |
1、除了加(+)之外,如果運算元不是Number類型,會自動調用Number()轉換為Number類型再進行計算。 2、對於加減(+-),除了作為算術運算子。還可以作為一元操作符(見上)。當然,由於字串操作中對加號(+)的重載,還可以用於將任意數值(的字串)相連,這也是第1點中為什麼要除了加(+),它在含有非Number類型值時,會將所有運算元轉換為字串相串連。 3、與一般類C語言不同,在ES中,除(/)和模數(%)並不會區分整數和浮點數,比如 5 / 2 = 2.5 而不是2,5.3 % 3 = 2.3 而不是2。 4、任意運算,只要運算元含NaN,結果就是NaN。但並不是結果為NaN就一定有一個運算元為NaN,比如0/0也返回NaN。 5、對於含無窮Infinity的運算,規定比較多,這裡就不列舉了,可以參考原書,或者自行測試。 |
| - |
減 |
| * |
乘 |
| / |
除 |
| % |
模數 |
| 邏輯操作符 (布爾操作符) |
! |
邏輯非 |
首先將運算元轉換為Boolean類型值,然後再取反。可以使用雙重非!!將一個數值轉換為相應的Boolean值。 |
| && |
邏輯與 |
1、當兩個運算元相應的Boolean值均為true時,返回true 2、短路:當第一個運算元相應的Boolean值為false時,會直接返回false,不會再計算第二個運算元。這常常被應用在判斷一個變數(屬性)是否有定義,如: if(object && object.name && object.name = 'linjisong'){ } 這裡會首先判斷object存在,不存在的話就不會解析object.name從而阻止錯誤的發生,同樣,也只有object.name存在,才會去比較這個值。 |
| || |
邏輯或 |
1、當兩個運算元相應的Boolean值至少有一個為true時,返回true 2、短路:當第一個運算元相應的Boolean值為true時,會直接返回true,不會再計算第二個運算元。 3、邏輯或,除了用於一般的判斷之外,還常常被應用在提供預設值的情況,如: function Fn(obj){ obj = obj || {}; } 這裡如果調用Fn未傳入obj,則會自動給obj賦值為undefined,然後因為undefined的相應Boolean值為false,所以會將一個Null 物件{}賦值給obj,如果調用傳入了obj,則因為任意對象的Boolean值為true,所以就不會取後面的{},從而達到給obj一個預設值{}的效果。 這種方式還被應用在大型JS庫的多個相對獨立的檔案中: //jsLib var jsLib; //file1 (function (jsLib){ jsLib = jsLib || {}; })(jsLib); //file2 (function (jsLib){ jsLib = jsLib || {}; })(jsLib); 使用這種方式,無論先載入哪個檔案,都會判斷jsLib是否已經定義,如果未定義就提供一個預設值,這樣做可以使得相對獨立模組可以不用考慮載入順序。
|
關係操作符 (比較操作符) |
< |
小於 |
1、只要有一個運算元是Number類型或Boolean類型值,就將兩個運算元轉換成Number類型值(如果需要轉換)執行數值比較。 2、字串比較,會逐個比較字元編碼值。 3、操作符是對象時,調用valueOf()(如果沒有,就調用toString()),再將結果按上面規則比較。 4、任意數和NaN比較返回false。 |
| <= |
小於或等於 |
| > |
大於 |
| >= |
大於或等於 |
| == |
相等 |
1、相等和不等(==、!=)在比較時,只要有必要,就會隱式類型轉換。 2、全等和不全等(===、!==)在比較時,不會轉換類型,如果類型不一致,直接為!==。 3、結合1、2,可以知道,a===b則一定有a==b,而a!=b則一定有a!==b。 |
| != |
不等 |
| === |
全等 |
| !== |
不全等 |
| 賦值操作符 |
= |
賦值 |
|
| 複合算術賦值操作符 |
算術運算子加= |
對應算術運算子,有+=、-=、*=、/=、%= |
| 複合按位賦值操作符 |
按位元運算符加= |
對應按位元運算符,有~=、&=、|=、^=、<<=、>>=、>>>= |
| 按位操作符 |
~ |
按位非 |
按位取反,也即返回反碼 |
| & |
按位與 |
按位對齊,逐位操作,只有兩個操作位均為1才返回1,否則該位返回0,最後將所有位操作結果組合返回 |
| | |
按位或 |
按位對齊,逐位操作,只有兩個操作位均為0才返回0,否則該位返回1,最後將所有位操作結果組合返回 |
| ^ |
按位異或 |
按位對齊,逐位操作,兩個操作位不相同時返回1,否則該位返回0,最後將所有位操作結果組合返回 |
| << |
左移 |
位元向左移位,左移不會改變符號位 |
| >> |
有符號右移 |
位元向右移位,高位以符合位填充 |
| >>> |
無符號右移 |
位元向右移位,直接右移,對於正數,結果和>>相同,對於負數,會把負數的二進位補碼當成正數的二進位碼處理 |
| 字串操作符 |
+ |
字串串連 |
相當於concat()函數,會先將所有運算元轉換為字串,然後再串連。注意,字串一旦建立就不會變更,執行字串串連時,在後台會有一個中間的串連和銷毀過程,這也是老舊瀏覽器在大量字串串連操作時運行緩慢的原因。 |
| += |
字串串連複合 |
a+=b,相當於a=a+b。 |
| 對象操作符 |
. |
屬性訪問符 |
簡單的對象屬性訪問符。 |
| [] |
屬性或(類)數組訪問 |
通過[],可以訪問名稱是一個變數或含有特殊字元的屬性。 |
| new |
調用建構函式建立對象 |
返回一個新建立的對象,在建構函式內部的this被指向這個新建立的對象。 |
| delete |
變數、屬性刪除 |
刪除屬性(變數可以看成是全域對象或執行環境的一個屬性)。 |
| void |
|
返回undefined。 |
| in |
判斷屬性 |
對象屬性或原型鏈上的屬性。 |
| instanceof |
原型判斷 |
比較同一個上下文中的對象是否為另一個對象的原型。 |
| 其它操作符 |
?: |
條件操作符 |
文法;var value = exp ? trueExp : falseExp。 相當於var value; if(exp){ value = trueExp;}else{value = falseExp;} |
| , |
逗號操作符 |
主要用於聲明多個變數,這也是很多JS庫的流行做法。例如:var num1=1,num2=2,num3=3; |
| () |
分組操作符 |
主要用途: 1、結合逗號操作符用於賦值。例如:var num = (5,1,4,8,0);這裡num最後的值為0。 2、轉換為運算式。比如eval('('+jsStr+')');又比如: function fn(){ }//函式宣告,不能直接調用 (function fn(){ })();//使用()將函數括起來,便可以直接調用 3、用於調用函數。比如fn();。 |
| typeof |
類型操作符 |
返回一個字串值:Undefined類型—>'undefined'、Null類型—>'object'、Boolean類型—>'boolean'、Number類型—>‘number'、String—>'string'、內建Function對象的執行個體—>'function'、其它Object類型—>'object'。(有些瀏覽器實現略有不同) |
說明幾點:
1、這裡的分類並不十分嚴格,比如按位非(~)、邏輯非(!)、delete、void、typeof,都可以算是一元操作符,而自增(++)在很多資料中也被歸為算術操作符之中。我在整理時則主要參考原書分類,也兼顧自然性。
2、加號(+)的用法比較靈活,需注意,特別是用於計算時,忽略了其中的字串,會很容易犯錯誤。
3、typeof一般用來判斷單一資料型別,如果是物件類型,因為大部分返回的都是object,沒有多大實際用處,而instanceof的判斷也需要滿足同一個內容相關的條件,否則也會出錯,對於物件類別的判斷會在後面講述對象時再詳細說明另外一種更為穩妥的方法。
4、先看下面的代碼:
複製代碼 代碼如下:
var numVal = 10.00,
strVal = '10',
strObj = new String('10');
console.info(numVal == strVal);//true
console.info(typeof (strVal+strObj));//string
第一個輸出的竟然是true,是不是出乎你的意料?在這裡,由於==比較符發生了隱式類型轉換,會將Number類型轉換為String類型,然後Number類型的10.00因為小數點後沒有不是0的數值,會被解析成整數10,從而比較的時候會相等。第二個輸出是string,這其實還是比較容易理解的,strVal是字串,strObj是字串對象,兩者相加,會把對象轉換成字串,所以最終結果也是字串類型。
5、關於符號,重複一下幾個流行的用法(這裡不涉及Regex中的用法):
(1)使用一元加號(+)轉換為Number類型。
(2)使用雙重邏輯非(!!)轉換為Boolean類型。
(3)使用邏輯與(&&)來檢測對象是否存在並進行後續操作。
(4)使用邏輯或(||)來給函數參數提供預設值。
(5)使用分組(())來明確指定為運算式。
(6)使用花括弧({})來定義對象字面量,JSON資料格式,代碼塊。
(7)使用中括弧([])來定義數組字面量,JSON資料格式,訪問數組,訪問名稱是變數或特殊字元的屬性。
6、關於按位元運算,雖然結果不是很直觀,但是運行效率高,也有很多有趣的應用,比如不使用中間變數直接交換兩個數值、判斷奇數和偶數、MD5加密等等,有興趣的朋友可以找相關資料自行研究。