表達式是由數字、運算符、數字分組符號(如括號)、自由變量和約束變量等以能求得數值的有意義排列方法所得的組合。JavaScript 表達式主要有如下幾種形式:javascript
var obj={a:1,b:2};
,var arr=[1,2,3];
。var fn=function(){}
。Math.abs
。alert('hello');
。new object();
。JavaScript 中的運算符用於算術表達式、比較表達式、邏輯表達式、賦值表達式等。須要注意的是,大多數運算符都是由標點符號表示的,好比 +
和 =
。而另一些運算符則是由關鍵字表示的,好比 typeof
和 instanceof
,關鍵字運算符和標點符號都是正規的運算符。java
下表列出了 JavaScript 中全部的運算符,並按照運算符的優先級排序的,前面的運算符優先級要高於後面的運算符優先級,被空行分隔開來的運算符具備不一樣的優先級。標題爲 A 的列表示運算符的結合性(Associativity),L 表示從左至右、R 表示從右至左,標題爲 N 的列表示操做數的個數(Number)。git
運算符 | 操做 | A | N |
---|---|---|---|
++ |
前/後增量 | R | 1 |
-- |
前/後增量 | R | 1 |
- |
求反 | R | 1 |
+ |
轉換爲數字 | R | 1 |
~ |
按位求反 | R | 1 |
! |
邏輯非 | R | 1 |
delete |
刪除屬性 | R | 1 |
typeof |
檢測類型 | R | 1 |
void |
返回undefined |
R | 1 |
* / % |
乘,除,求模 | L | 2 |
+ - |
加,減 | L | 2 |
+ |
字符串鏈接 | L | 2 |
<< |
左移位 | L | 2 |
>> |
有符號右移 | L | 2 |
>>> |
無符號右移 | L | 2 |
< <= > >= |
比較數字順序 | L | 2 |
< <= > >= |
比較字母順序 | L | 2 |
instanceof |
測試對象類 | L | 2 |
in |
測試屬性是否存在 | L | 2 |
== |
判斷相等 | L | 2 |
!= |
判斷不等 | L | 2 |
=== |
判斷恆等 | L | 2 |
!== |
判斷恆不等 | L | 2 |
& |
按位與 | L | 2 |
^ |
按位異或 | L | 2 |
┃ |
按位或 | L | 2 |
&& |
邏輯與 | L | 2 |
┃┃ |
邏輯或 | L | 2 |
?: |
條件運算符 | R | 3 |
= |
賦值 | R | 2 |
*= /= %= += -= &= <<= >>= ^= ┃= >>>= |
運算且賦值 | R | 2 |
, |
忽略第一個操做數, 返回第二個操做數 |
L | 2 |
由於
|
是製表符,會致使格式混亂,因此表格中的|
均以┃
代替。github
delete
運算符delete
運算符用來刪除對象屬性或者數組元素,若是刪除成功或所刪除的目標不存在,delete
將返回 true
。然而,並非全部的屬性均可刪除,一些內置核心和客戶端屬性是不能刪除的,經過 var
語句聲明的變量不能刪除,經過 function
語句定義的函數也是不能刪除的。例如:正則表達式
var o = { x: 1, y: 2}; // 定義一個對象
console.log(delete o.x); // true,刪除一個屬性
console.log(delete o.x); // true,什麼都沒作,x 在已上一步被刪除
console.log("x" in o); // false,這個屬性在對象中再也不存在
console.log(delete o.toString); // true,什麼也沒作,toString是繼承來的
console.log(delete 1); // true,無心義
var a = [1,2,3]; // 定義一個數組
console.log(delete a[2]); // true,刪除最後一個數組元素
console.log(2 in a); // false,元素2在數組中再也不存在
console.log(a.length); // 3,數組長度並不會因 delete 而改變
console.log(a[2]); // undefined,元素2所在的位置被空了出來
console.log(delete a); // false,經過 var 語句聲明的變量不能刪除
function f(args){} // 定義一個函數
console.log(delete f); // false,經過 function 語句聲明的函數不能刪除複製代碼
void
運算符void
運算符能夠應用於任何表類型的表達式,表達式會被執行,但計算結果會被忽略並返回 undefined
。例如:express
void 0;
void "you are useless?";
void false;
void [];
void /(useless)/ig;
void function(){ console.log("you are so useless?"); }
// always return undefined複製代碼
擴展閱讀「談談 JavaScript 中的 void 運算符」
segmentfault.com/a/119000000…編程
typeof
運算符請參見「變量和數據類型」-「數據類型」-「
typeof
運算符」。segmentfault
++
--
運算符++
--
遞增遞減運算符借鑑自 C 語言,它們分前置型和後置型,做用是改變一個變量的值。例如:數組
var a = 5;
console.log(a++); // 5
console.log(++a); // 7
console.log(a--); // 7
console.log(--a); // 5複製代碼
+
-
運算符當 +
-
做爲一元運算符時,應用於數值,表示數值的正負。應用於非數值,先按 Number()
轉型函數對這個值執行轉換,再表示該值的正負。微信
~
!
運算符JavaScript 定義了3個乘性運算符:乘法、除法和求模。這些運算符與 C 語言的相應運算符用途相似,只不過在操做數爲非數值的狀況下會執行自動的類型轉換。若是參與乘法計算的某個操做數不是數值,後臺會先使用 Number()
轉型函數將其轉換爲數值。也就是說,空字符串將被看成 0
,布爾值 true
將被看成 1
。
*
乘法運算符用於計算兩個數值的乘積,在處理特殊值的狀況下,乘法運算符遵循下列特殊的規則:
Infinity
或 -Infinity
;NaN
,則結果是 NaN
;Infinity
與 0
相乘,則結果是 NaN
;Infinity
與非 0
數值相乘,則結果是 Infinity
或 -Infinity
,取決於有符號操做數的符號;Infinity
與 Infinity
相乘,則結果是 Infinity
;Number()
將其轉換爲數值,而後再應用上面的規則。/
除法運算符用於計算兩個數值的商,與乘法運算符相似,除法運算符對特殊的值也有特殊的處理規則。這些規則以下:
Infinity
或 -Infinity
;NaN
,則結果是 NaN
;Infinity
被 Infinity
除,則結果是 NaN
;NaN
;Infinity
或 -Infinity
,取決於有符號操做數的符號;Infinity
被任何非零數值除,則結果是 Infinity
或 -Infinity
,取決於有符號操做數的符號;Number()
將其轉換爲數值,而後再應用上面的規則。%
求模運算符用於計算兩個數值的餘數,與另外兩個乘性運算符相似,求模運算符會遵循下列特殊規則來處理特殊的值:
NaN
;NaN
;Infinity
被 Infinity
除,則結果是 NaN
;Number()
將其轉換爲數值,而後再應用上面的規則。加法和減法這兩個加性運算符應該說是編程語言中最簡單的算術運算符了。可是在 JavaScript 中,這兩個運算符卻都有一系列的特殊行爲。與乘性運算符相似,加性運算符也會在後臺轉換不一樣的數據類型。然而,對於加性運算符而言,相應的轉換規則還稍微有點複雜。
+
加法運算符若是兩個運算符都是數值,執行常規的加法計算,而後根據下列規則返回結果:
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"
。null
加 null
,則結果是 0
;undefined
加 undefined
,則結果是 NaN
;下面來舉幾個例子:
var result1 = 5 + 5; // 兩個數值相加
console.log(result1); // 10
var result2 = 5 + "5"; // 一個數值和一個字符串相加
console.log(result2); // "55"
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + num1 + num2;
console.log(message); // "The sum of 5 and 10 is 510",如何修改?複製代碼
-
減法運算符若是兩個運算符都是數值,執行常規的減法計算,而後根據下列規則返回結果:
NaN
,則結果是 NaN
;Infinity
減 Infinity
,則結果是 NaN
;-Infinity
減 -Infinity
,則結果是 NaN
;Infinity
減 -Infinity
,則結果是 Infinity
;-Infinity
減 Infinity
,則結果是 -Infinity
;+0
減 +0
,則結果是 +0
;+0
減 -0
,則結果是 -0
;-0
減 -0
,則結果是 +0
;若是有一個操做數不是數值,那麼就要應用以下規則:
null
或 undefined
,則先在後臺調用 Number()
函數將其轉換爲數值,而後再根據前面的規則執行減法計算。若是轉換的結果是 NaN
,則減法的結果就是 NaN
;valueOf()
方法以取得表示該對象的數值。若是獲得的值是 NaN
,則減法的結果就是 NaN
。若是對象沒有 valueOf()
方法,則調用其 toString()
方法並將獲得的字符串轉換爲數值。null
減 null
,則結果是 0
;undefined
減 undefined
,則結果是 NaN
;下面來舉幾個例子:
var result1 = 5 - true; // 4,由於true被轉換成了1
var result2 = NaN - 1; // NaN
var result3 = 5 - 3; // 2
var result4 = 5 - ""; // 5,由於"" 被轉換成了0
var result5 = 5 - "2"; // 3,由於"2"被轉換成了2
var result6 = 5 - null; // 5,由於null被轉換成了0複製代碼
肯定兩個變量是否相等是編程中的一個很是重要的操做。在比較簡單數據類型之間的相等性時,問題還比較簡單。但在涉及到對象之間的比較時,問題就變得複雜了。最先的 JavaScript 中的相等和不等運算符會在執行比較以前,先將對象轉換成類似的類型。後來,有人提出了這種轉換究竟是否合理的質疑。最後,JavaScript 的解決方案就是提供兩組運算符:相等和不相等(先轉換再比較),恆等和不恆等(僅比較而不轉換)。
==
!=
運算符==
!=
這兩個運算符都會先轉換操做數(一般稱爲強制轉型),而後再比較它們的相等性。在轉換不一樣的數據類型時,相等和不相等運算符遵循下列基本規則:
false
轉換爲 0
,而 true
轉換爲 1
);valueOf()
方法,用獲得的基本類型值按照前面的規則進行比較;null
和 undefined
是相等的。null
和 undefined
轉換成其餘任何值。NaN
,則相等運算符返回 false
,而不相等運算符返回 true
。重要提示:即便兩個操做數都是 NaN
,相等運算符也返回 false
;由於按照規則,NaN
不等於 NaN
。true
;不然,返回 false
。列出了一些特殊狀況及比較結果:
null == undefined // true
"NaN" == NaN // false
5 == NaN // false
NaN == NaN // false
NaN != NaN // true
false == 0 // true
true == 1 // true
true == 2 // false
undefined == 0 // false
null == 0 // false
"5" == 5 // true複製代碼
===
!==
運算符除了在比較以前不轉換操做數以外,恆等和不恆等運算符與相等和不相等運算符沒有什麼區別。它只在兩個操做數未經轉換就相等的狀況下返回 true
,以下面的例子所示:
var result1 = ("55" == 55); // true,由於轉換後相等
var result2 = ("55" === 55); // false,由於不一樣的數據類型不相等
var result3 = (null == undefined) // true,由於它們是相似的值
var result4 = (null === undefined) // false,由於它們是不一樣類型的值複製代碼
<
>
<=
>=
運算符<
小於、>
大於、<=
小於等於、 >=
大於等於 這幾個關係運算符用於對兩個值進行比較返回一個布爾值。與 JavaScript 中的其餘運算符同樣,當關系運算符的操做數使用了非數值時,也要進行數據轉換或完成某些奇怪的操做。如下就是相應的規則。
charCodeAt()
函數獲取字符編碼值)。valueOf()
方法,用獲得的結果按照前面的規則執行比較。若是對象沒有 valueOf()
方法,則調用 toString()
方法,並用獲得的結果根據前面的規則執行比較。請思考下面幾個例子的結果是如何得出的:
var result1 = "Brick" < "alphabet"; // true
var result2 = "brick" < "alphabet"; // false
var result3 = "23" < "3"; // true
var result4 = "23" < 3; // false
var result5 = "a" < 3; // false
var result6 = NaN < 3; // false
var result7 = NaN >= 3; // false複製代碼
in
運算符in
運算符但願它的左操做數是一個字符串或能夠轉換爲字符串,但願它的右操做數是一個對象。若是右側的對象擁有一個名爲左操做數值的屬性名,那麼表達式返回 true
,例如:
var point = { x:1, y:1 }; // 定義一個對象
"x" in point // true,對象有一個名爲"x"的屬性
"z" in point // false,對象中不存在名爲"z"的屬性
"toString" in point // true,對象繼承了toString()方法
var data = [7,8,9]; // 擁有三個元素的數組
"0" in data // true,數組包含元素"0"
1 in data // true,數字轉換爲字符串
3 in data // false,沒有索引爲3的元素複製代碼
instanceof
運算符instanceof
運算符但願左操做數是一個對象,右操做數標識對象的類。若是左側的對象是右側類的實例,則表達式返回 true
;不然返回 false
。後面會講 JavaScript 中對象的類是經過初始化它們的構造函數來定義的。這樣的話,instanceof
的右操做數應當是一個函數。好比:
var d = new Date(); // 經過 Date() 構造函數來建立一個新對象
d instanceof Date; // true,d 是由 Date() 建立的
d instanceof Object; // true,全部的對象都是 Object 的實例
d instanceof Number; // false,d 不是一個 Number 對象
var a = [1, 2, 3]; // 經過數組字面量的寫法建立一個數組
a instanceof Array; // true,a 是一個數組
a instanceof Object; // true,全部的數組都是對象
a instanceof RegExp; // false,數組不是正則表達式複製代碼
須要注意的是,全部的對象都是 Object
的實例。當經過 instanceof
判斷一個對象是不是一個類的實例的時候,這個判斷也會包含對「父類」的檢測。若是 instanceof
的左操做數不是對象的話,instanceof
返回 false
。若是右操做數不是函數,則拋出一個類型錯誤異常。
邏輯運算符是對操做數進行布爾算術運算,常常和關係運算符一塊兒配合使用,邏輯運算符將多個關係表達式組合起來組成一個更復雜的表達式。
&&
邏輯與邏輯與操做能夠應用於任何類型的操做數,而不只僅是布爾值。在有一個操做數不是布爾值的狀況下,邏輯與操做不必定返回布爾值;此時,它遵循下列規則:
true
的狀況下才會返回該對象;null
,則返回 null
;NaN
,則返回 NaN
;undefined
,則返回 undefined
。邏輯與操做屬於短路操做,即若是第一個操做數可以決定結果,那麼就不會再對第二個操做數求值。對於邏輯與操做而言,若是第一個操做數是 false
,不管第二個操做數是什麼值,結果都再也不多是 true
了。
||
邏輯或與邏輯與操做類似,若是有一個操做數不是布爾值,邏輯或也不必定返回布爾值;此時,它遵循下列規則:
false
,則返回第二個操做數;null
,則返回 null
;NaN
,則返回 NaN
;undefined
,則返回 undefined
。與邏輯與運算符類似,邏輯或運算符也是短路運算符。也就是說,若是第一個操做數的求值結果爲 true
,就不會對第二個操做數求值了。
!
邏輯非邏輯非操做能夠應用於任何類型的操做數,不管這個值是什麼數據類型,這個運算符都會返回一個布爾值。邏輯非運算符首先會將它的操做數轉換爲一個布爾值,而後再對其求反。邏輯非運算符遵循下列規則:
false
;true
;false
;0
,返回 true
;0
數值(包括 Infinity
),返回 false
;null
,返回 true
;NaN
,返回 true
;undefined
,返回 true
。下面幾個例子展現了應用上述規則的結果:
console.log(!false); // true
console.log(!"blue"); // false
console.log(!0); // true
console.log(!NaN); // true
console.log(!""); // true
console.log(!12345); // false複製代碼
邏輯非運算符也能夠用於將一個值轉換爲與其對應的布爾值。而同時使用兩個邏輯非運算符,實際上就會模擬 Boolean()
轉型函數的行爲。其中,第一個邏輯非操做會基於不管什麼操做數返回一個布爾值,而第二個邏輯非操做則對該布爾值求反,因而就獲得了這個值真正對應的布爾值。固然,最終結果與對這個值使用 Boolean()
函數相同,例如:
console.log(!!"blue"); //true
console.log(!!0); //false
console.log(!!NaN); //false
console.log(!!""); //false
console.log(!!12345); //true複製代碼
在 JavaScript 中,當對數值應用位運算符時,後臺會發生以下轉換過程:64位的數值被轉換成32位數值,而後執行位操做,最後再將32位的結果轉換回64位數值。這個轉換過程致使了一個嚴重的副效應,即在對特殊的 NaN
和 Infinity
值應用位操做時,這兩個值都會被當成 0
來處理。若是對非數值應用位運算符,會先使用 Number()
函數將該值轉換爲一個數值,而後再應用位操做,獲得的結果將是一個數值。
~
按位非簡單的理解,對任一數值 x
進行按位非操做的結果爲 -(x+1)
。例如:
console.log(~null); // -1
console.log(~undefined); // -1
console.log(~0); // -1
console.log(~{}); // -1
console.log(~[]); // -1
console.log(~(1/0)); // -1
console.log(~false); // -1
console.log(~true); // -2
console.log(~1.2543); // -2
console.log(~4.9); // -5
console.log(~(-2.999)); // 1複製代碼
&
按位與按位與操做就是將兩個數值的每一位對齊,兩個數值的對應位都是 1
時才返回 1
,任何一位是 0
,結果都是 0
。以下表所示:
第一個數值的位 | 第二個數值的位 | 結果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
|
按位或按位或操做就是將兩個數值的每一位對齊,兩個數值只要有一個位是 1
就返回 1
,只在兩個位都是 0
的狀況下才返回 0
。以下表所示:
第一個數值的位 | 第二個數值的位 | 結果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
^
按位異或按位異或與按位或的不一樣之處在於,兩個數值只有一個 1
時才返回 1
,若是對應的兩位都是 1
或都是 0
,則返回 0
。
第一個數值的位 | 第二個數值的位 | 結果 |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
<<
左移這個運算符會將數值的全部位向左移動指定的位數。例如:
var oldValue = 2; // 等於二進制的 10
var newValue = oldValue << 5; // 等於二進制的 1000000,十進制的 64複製代碼
注意,左移不會影響操做數的符號位。換句話說,若是將 -2
向左移動 5
位,結果將是 -64
,而非 64
。
>>
有符號的右移這個運算符會將數值向右移動,但保留符號位(即正負號標記)。
var oldValue = 64; // 等於二進制的 1000000
var newValue = oldValue >> 5; // 等於二進制的 10 ,即十進制的 2複製代碼
>>>
無符號的右移這個運算符會將數值的全部32位都向右移動。對正數來講,無符號右移的結果與有符號右移相同。
var oldValue = 64; // 等於二進制的 1000000
var newValue = oldValue >>> 5; // 等於二進制的 10 ,即十進制的 2複製代碼
無符號右移運算符會把負數的二進制碼當成正數的二進制碼。並且,因爲負數以其絕對值的二進制補碼形式表示,所以就會致使無符號右移後的結果很是之大。
var oldValue = -64; // 等於二進制的 11111111111111111111111111000000
var newValue = oldValue >>> 5; // 等於十進制的 134217726複製代碼
簡單的賦值運算符由等於號 =
表示,其做用就是把右側的值賦給左側的變量,以下面的例子所示:
var num = 10;複製代碼
若是在等於號 =
前面再添加乘性運算符、加性運算符或位運算符,就能夠完成複合賦值操做。這種複合賦值操做至關因而對下面常規表達式的簡寫形式:
var num = 10;
num += 10; // 等同於 num = num + 10;複製代碼
每一個主要算術運算符(以及個別的其餘運算符)都有對應的複合賦值運算符。這些運算符以下所示:
*=
;/=
;%=
;+=
;-=
;<<=
;>>=
;>>>=
。設計這些運算符的主要目的就是簡化賦值操做,使用它們不會帶來任何性能的提高。
? :
條件運算符應該算是 JavaScript 中最靈活的一種運算符了,並且它遵循與 Java 中的條件運算符相同的語法形式,以下面的例子所示:
variable = boolean_expression ? true_value : false_value;複製代碼
逗號運算符多用於聲明多個變量;但除此以外,逗號運算符還能夠用於賦值。在用於賦值時,逗號運算符總會返回表達式中的最後一項,以下面的例子所示:
var num = (5, 1, 4, 8, 0); // num 的值爲 0複製代碼
因爲 0
是表達式中的最後一項,所以 num
的值就是 0
。雖然逗號的這種使用方式並不常見,但這個例子能夠幫咱們理解逗號的這種行爲。
// 挑戰一
var x=1;
if(!!function f(){}){
x+=typeof f;
}
console.log(x); // ???複製代碼
// 挑戰二
(function f(f){
console.log(typeof f()); // ???
})(function(){return 1;});複製代碼
// 挑戰三
console.log(typeof 2*3); // ???
console.log(typeof 2+3); // ???複製代碼
// 挑戰四
var a=0,b=0;
console.log(a+++b); // ???
console.log(a); // ???
console.log(b); // ???複製代碼
// 挑戰五
var a,b,c;
a=b==c;
console.log(a); // ???複製代碼
// 挑戰六
console.log(1 && 3); // ???
console.log(1 && "foo" || 0); // ???
console.log(1 || "foo" && 0); // ???複製代碼
// 挑戰七
var a=1;
var b=(a=(2,4,6))+a++
console.log(b); // ???複製代碼
// 挑戰八
if (!("a" in window)) {
var a = 1;
}
console.log(a); // ???複製代碼
// 挑戰九
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing'); // ???複製代碼
// 挑戰九
console.log(1 + - + + + - + 1);複製代碼
關注微信公衆號「劼哥舍」回覆「答案」,獲取關卡詳解。
關注 github.com/stone0090/j…,獲取最新動態。