表達式
表達式是由數(shù)字、運算符、數(shù)字分組符號(如括號)、自由變量和約束變量等以能求得數(shù)值的有意義排列方法所得的組合。JavaScript 表達式主要有以下幾種形式:
- 原始表達式:常量、變量、保留字。
- 對象、數(shù)組初始化表達式:
var obj={a:1,b:2};,var arr=[1,2,3];。 - 函數(shù)定義表達式:
var fn=function(){}。 - 屬性訪問表達式:
Math.abs。 - 調用表達式:
alert('hello');。 - 對象創(chuàng)建表達式:
new object();。
運算符
JavaScript 中的運算符用于算術表達式、比較表達式、邏輯表達式、賦值表達式等。需要注意的是,大多數(shù)運算符都是由標點符號表示的,比如 + 和 =。而另外一些運算符則是由關鍵字表示的,比如 typeof 和 instanceof,關鍵字運算符和標點符號都是正規(guī)的運算符。
下表列出了 JavaScript 中所有的運算符,并按照運算符的優(yōu)先級排序的,前面的運算符優(yōu)先級要高于后面的運算符優(yōu)先級,被空行分隔開來的運算符具有不同的優(yōu)先級。標題為 A 的列表示運算符的結合性(Associativity),L 表示從左至右、R 表示從右至左,標題為 N 的列表示操作數(shù)的個數(shù)(Number)。
| 運算符 | 操作 | A | N |
|---|---|---|---|
++ |
前/后增量 | R | 1 |
-- |
前/后增量 | R | 1 |
- |
求反 | R | 1 |
+ |
轉換為數(shù)字 | 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 |
< <= > >=
|
比較數(shù)字順序 | 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 |
, |
忽略第一個操作數(shù), 返回第二個操作數(shù) |
L | 2 |
因為
|是制表符,會導致格式混亂,所以表格中的|均以┃代替。
一元運算符
delete 運算符
delete 運算符用來刪除對象屬性或者數(shù)組元素,如果刪除成功或所刪除的目標不存在,delete 將返回 true。然而,并不是所有的屬性都可刪除,一些內置核心和客戶端屬性是不能刪除的,通過 var 語句聲明的變量不能刪除,通過 function 語句定義的函數(shù)也是不能刪除的。例如:
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]; // 定義一個數(shù)組
console.log(delete a[2]); // true,刪除最后一個數(shù)組元素
console.log(2 in a); // false,元素2在數(shù)組中不再存在
console.log(a.length); // 3,數(shù)組長度并不會因 delete 而改變
console.log(a[2]); // undefined,元素2所在的位置被空了出來
console.log(delete a); // false,通過 var 語句聲明的變量不能刪除
function f(args){} // 定義一個函數(shù)
console.log(delete f); // false,通過 function 語句聲明的函數(shù)不能刪除
void 運算符
void 運算符可以應用于任何表類型的表達式,表達式會被執(zhí)行,但計算結果會被忽略并返回 undefined。例如:
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 運算符」
https://segmentfault.com/a/1190000000474941
typeof 運算符
++ -- 運算符
++ -- 遞增遞減運算符借鑒自 C 語言,它們分前置型和后置型,作用是改變一個變量的值。例如:
var a = 5;
console.log(a++); // 5
console.log(++a); // 7
console.log(a--); // 7
console.log(--a); // 5
+ - 運算符
當 + - 作為一元運算符時,應用于數(shù)值,表示數(shù)值的正負。應用于非數(shù)值,先按 Number() 轉型函數(shù)對這個值執(zhí)行轉換,再表示該值的正負。
~ ! 運算符
乘性運算符
JavaScript 定義了3個乘性運算符:乘法、除法和求模。這些運算符與 C 語言的相應運算符用途類似,只不過在操作數(shù)為非數(shù)值的情況下會執(zhí)行自動的類型轉換。如果參與乘法計算的某個操作數(shù)不是數(shù)值,后臺會先使用 Number() 轉型函數(shù)將其轉換為數(shù)值。也就是說,空字符串將被當作 0,布爾值 true 將被當作 1。
* 乘法運算符
用于計算兩個數(shù)值的乘積,在處理特殊值的情況下,乘法運算符遵循下列特殊的規(guī)則:
- 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的乘法計算,即兩個正數(shù)或兩個負數(shù)相乘的結果還是正數(shù),而如果只有一個操作數(shù)有符號,那么結果就是負數(shù)。如果乘積超過了 JavaScript 數(shù)值的表示范圍,則返回
Infinity或-Infinity; - 如果有一個操作數(shù)是
NaN,則結果是NaN; - 如果是
Infinity與0相乘,則結果是NaN; - 如果是
Infinity與非0數(shù)值相乘,則結果是Infinity或-Infinity,取決于有符號操作數(shù)的符號; - 如果是
Infinity與Infinity相乘,則結果是Infinity;
如果有一個操作數(shù)不是數(shù)值,則在后臺調用Number()將其轉換為數(shù)值,然后再應用上面的規(guī)則。
/ 除法運算符
用于計算兩個數(shù)值的商,與乘法運算符類似,除法運算符對特殊的值也有特殊的處理規(guī)則。這些規(guī)則如下:
- 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的除法計算,即兩個正數(shù)或兩個負數(shù)相除的結果還是正數(shù),而如果只有一個操作數(shù)有符號,那么結果就是負數(shù)。如果商超過了 JavaScript 數(shù)值的表示范圍,則返回
Infinity或-Infinity; - 如果有一個操作數(shù)是
NaN,則結果是NaN; - 如果是
Infinity被Infinity除,則結果是NaN; - 如果是零被零除,則結果是
NaN; - 如果是非零的有限數(shù)被零除,則結果是
Infinity或-Infinity,取決于有符號操作數(shù)的符號; - 如果是
Infinity被任何非零數(shù)值除,則結果是Infinity或-Infinity,取決于有符號操作數(shù)的符號; - 如果有一個操作數(shù)不是數(shù)值,則在后臺調用
Number()將其轉換為數(shù)值,然后再應用上面的規(guī)則。
% 求模運算符
用于計算兩個數(shù)值的余數(shù),與另外兩個乘性運算符類似,求模運算符會遵循下列特殊規(guī)則來處理特殊的值:
- 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的除法計算,返回除得的余數(shù);
- 如果被除數(shù)是無窮大值而除數(shù)是有限大的數(shù)值,則結果是
NaN; - 如果被除數(shù)是有限大的數(shù)值而除數(shù)是零,則結果是
NaN; - 如果是
Infinity被Infinity除,則結果是NaN; - 如果被除數(shù)是有限大的數(shù)值而除數(shù)是無窮大的數(shù)值,則結果是被除數(shù);
- 如果被除數(shù)是零,則結果是零;
- 如果有一個操作數(shù)不是數(shù)值,則在后臺調用
Number()將其轉換為數(shù)值,然后再應用上面的規(guī)則。
加性運算符
加法和減法這兩個加性運算符應該說是編程語言中最簡單的算術運算符了。但是在 JavaScript 中,這兩個運算符卻都有一系列的特殊行為。與乘性運算符類似,加性運算符也會在后臺轉換不同的數(shù)據(jù)類型。然而,對于加性運算符而言,相應的轉換規(guī)則還稍微有點復雜。
+ 加法運算符
如果兩個運算符都是數(shù)值,執(zhí)行常規(guī)的加法計算,然后根據(jù)下列規(guī)則返回結果:
- 如果有一個操作數(shù)是
NaN,則結果是NaN; - 如果是
Infinity加Infinity,則結果是Infinity; - 如果是
-Infinity加-Infinity,則結果是-Infinity; - 如果是
Infinity加-Infinity,則結果是NaN; - 如果是
+0加+0,則結果是+0; - 如果是
-0加-0,則結果是-0; - 如果是
+0加-0,則結果是+0;
如果有一個操作數(shù)不是數(shù)值,那么就要應用如下規(guī)則:
- 如果兩個操作數(shù)都是字符串,則將第二個操作數(shù)與第一個操作數(shù)拼接起來;
- 如果只有一個操作數(shù)是字符串,則將另一個操作數(shù)轉換為字符串,然后再將兩個字符串拼接起來。
- 如果有一個操作數(shù)是對象、數(shù)值或布爾值,則調用它們的
toString()方法取得相應的字符串值,然后再應用前面關于字符串的規(guī)則。對于undefined和null,則分別調用String()函數(shù)并取得字符串"undefined"和"null"。 - 如果是
null加null,則結果是0; - 如果是
undefined加undefined,則結果是NaN;
下面來舉幾個例子:
var result1 = 5 + 5; // 兩個數(shù)值相加
console.log(result1); // 10
var result2 = 5 + "5"; // 一個數(shù)值和一個字符串相加
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",如何修改?
- 減法運算符
如果兩個運算符都是數(shù)值,執(zhí)行常規(guī)的減法計算,然后根據(jù)下列規(guī)則返回結果:
- 如果有一個操作數(shù)是
NaN,則結果是NaN; - 如果是
Infinity減Infinity,則結果是NaN; - 如果是
-Infinity減-Infinity,則結果是NaN; - 如果是
Infinity減-Infinity,則結果是Infinity; - 如果是
-Infinity減Infinity,則結果是-Infinity; - 如果是
+0減+0,則結果是+0; - 如果是
+0減-0,則結果是-0; - 如果是
-0減-0,則結果是+0;
如果有一個操作數(shù)不是數(shù)值,那么就要應用如下規(guī)則:
- 如果有一個操作數(shù)是字符串、布爾值、
null或undefined,則先在后臺調用Number()函數(shù)將其轉換為數(shù)值,然后再根據(jù)前面的規(guī)則執(zhí)行減法計算。如果轉換的結果是NaN,則減法的結果就是NaN; - 如果有一個操作數(shù)是對象,則調用對象的
valueOf()方法以取得表示該對象的數(shù)值。如果得到的值是NaN,則減法的結果就是NaN。如果對象沒有valueOf()方法,則調用其toString()方法并將得到的字符串轉換為數(shù)值。 - 如果是
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
等值運算符
確定兩個變量是否相等是編程中的一個非常重要的操作。在比較簡單數(shù)據(jù)類型之間的相等性時,問題還比較簡單。但在涉及到對象之間的比較時,問題就變得復雜了。最早的 JavaScript 中的相等和不等運算符會在執(zhí)行比較之前,先將對象轉換成相似的類型。后來,有人提出了這種轉換到底是否合理的質疑。最后,JavaScript 的解決方案就是提供兩組運算符:相等和不相等(先轉換再比較),恒等和不恒等(僅比較而不轉換)。
== != 運算符
== != 這兩個運算符都會先轉換操作數(shù)(通常稱為強制轉型),然后再比較它們的相等性。在轉換不同的數(shù)據(jù)類型時,相等和不相等運算符遵循下列基本規(guī)則:
- 如果有一個操作數(shù)是布爾值,則在比較相等性之前先將其轉換為數(shù)值(
false轉換為0,而true轉換為1); - 如果一個操作數(shù)是字符串,另一個操作數(shù)是數(shù)值,在比較相等性之前先將字符串轉換為數(shù)值;
- 如果一個操作數(shù)是對象,另一個操作數(shù)不是,則調用對象的
valueOf()方法,用得到的基本類型值按照前面的規(guī)則進行比較; -
null和undefined是相等的。
要比較相等性之前,不能將null和undefined轉換成其他任何值。 - 如果有一個操作數(shù)是
NaN,則相等運算符返回false,而不相等運算符返回true。重要提示:即使兩個操作數(shù)都是NaN,相等運算符也返回false;因為按照規(guī)則,NaN不等于NaN。 - 如果兩個操作數(shù)都是對象,則比較它們是不是同一個對象。如果兩個操作數(shù)都指向同一個對象,則相等運算符返回
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
=== !== 運算符
除了在比較之前不轉換操作數(shù)之外,恒等和不恒等運算符與相等和不相等運算符沒有什么區(qū)別。它只在兩個操作數(shù)未經(jīng)轉換就相等的情況下返回 true,如下面的例子所示:
var result1 = ("55" == 55); // true,因為轉換后相等
var result2 = ("55" === 55); // false,因為不同的數(shù)據(jù)類型不相等
var result3 = (null == undefined) // true,因為它們是類似的值
var result4 = (null === undefined) // false,因為它們是不同類型的值
關系運算符
< > <= >= 運算符
< 小于、> 大于、<= 小于等于、 >= 大于等于 這幾個關系運算符用于對兩個值進行比較返回一個布爾值。與 JavaScript 中的其他運算符一樣,當關系運算符的操作數(shù)使用了非數(shù)值時,也要進行數(shù)據(jù)轉換或完成某些奇怪的操作。以下就是相應的規(guī)則。
- 如果兩個操作數(shù)都是數(shù)值,則執(zhí)行數(shù)值比較。
- 如果兩個操作數(shù)都是字符串,則比較兩個字符串對應的字符編碼值(可以通過字符串的
charCodeAt()函數(shù)獲取字符編碼值)。 - 如果一個操作數(shù)是數(shù)值,則將另一個操作數(shù)轉換為一個數(shù)值,然后執(zhí)行數(shù)值比較。
- 如果一個操作數(shù)是對象,則調用這個對象的
valueOf()方法,用得到的結果按照前面的規(guī)則執(zhí)行比較。如果對象沒有valueOf()方法,則調用toString()方法,并用得到的結果根據(jù)前面的規(guī)則執(zhí)行比較。 - 如果一個操作數(shù)是布爾值,則先將其轉換為數(shù)值,然后再執(zhí)行比較。
請思考下面幾個例子的結果是如何得出的:
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 運算符希望它的左操作數(shù)是一個字符串或可以轉換為字符串,希望它的右操作數(shù)是一個對象。如果右側的對象擁有一個名為左操作數(shù)值的屬性名,那么表達式返回 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]; // 擁有三個元素的數(shù)組
"0" in data // true,數(shù)組包含元素"0"
1 in data // true,數(shù)字轉換為字符串
3 in data // false,沒有索引為3的元素
instanceof 運算符
instanceof 運算符希望左操作數(shù)是一個對象,右操作數(shù)標識對象的類。如果左側的對象是右側類的實例,則表達式返回 true;否則返回 false。后面會講 JavaScript 中對象的類是通過初始化它們的構造函數(shù)來定義的。這樣的話,instanceof 的右操作數(shù)應當是一個函數(shù)。比如:
var d = new Date(); // 通過 Date() 構造函數(shù)來創(chuàng)建一個新對象
d instanceof Date; // true,d 是由 Date() 創(chuàng)建的
d instanceof Object; // true,所有的對象都是 Object 的實例
d instanceof Number; // false,d 不是一個 Number 對象
var a = [1, 2, 3]; // 通過數(shù)組字面量的寫法創(chuàng)建一個數(shù)組
a instanceof Array; // true,a 是一個數(shù)組
a instanceof Object; // true,所有的數(shù)組都是對象
a instanceof RegExp; // false,數(shù)組不是正則表達式
需要注意的是,所有的對象都是 Object 的實例。當通過 instanceof 判斷一個對象是否是一個類的實例的時候,這個判斷也會包含對「父類」的檢測。如果 instanceof 的左操作數(shù)不是對象的話,instanceof 返回 false。如果右操作數(shù)不是函數(shù),則拋出一個類型錯誤異常。
邏輯運算符
邏輯運算符是對操作數(shù)進行布爾算術運算,經(jīng)常和關系運算符一起配合使用,邏輯運算符將多個關系表達式組合起來組成一個更復雜的表達式。
&& 邏輯與
邏輯與操作可以應用于任何類型的操作數(shù),而不僅僅是布爾值。在有一個操作數(shù)不是布爾值的情況下,邏輯與操作不一定返回布爾值;此時,它遵循下列規(guī)則:
- 如果第一個操作數(shù)是對象,則返回第二個操作數(shù);
- 如果第二個操作數(shù)是對象,則只有在第一個操作數(shù)的求值結果為
true的情況下才會返回該對象; - 如果兩個操作數(shù)都是對象,則返回第二個操作數(shù);
- 如果有一個操作數(shù)是
null,則返回null; - 如果有一個操作數(shù)是
NaN,則返回NaN; - 如果有一個操作數(shù)是
undefined,則返回undefined。
邏輯與操作屬于短路操作,即如果第一個操作數(shù)能夠決定結果,那么就不會再對第二個操作數(shù)求值。對于邏輯與操作而言,如果第一個操作數(shù)是 false,無論第二個操作數(shù)是什么值,結果都不再可能是 true 了。
|| 邏輯或
與邏輯與操作相似,如果有一個操作數(shù)不是布爾值,邏輯或也不一定返回布爾值;此時,它遵循下列規(guī)則:
- 如果第一個操作數(shù)是對象,則返回第一個操作數(shù);
- 如果第一個操作數(shù)的求值結果為
false,則返回第二個操作數(shù); - 如果兩個操作數(shù)都是對象,則返回第一個操作數(shù);
- 如果兩個操作數(shù)都是
null,則返回null; - 如果兩個操作數(shù)都是
NaN,則返回NaN; - 如果兩個操作數(shù)都是
undefined,則返回undefined。
與邏輯與運算符相似,邏輯或運算符也是短路運算符。也就是說,如果第一個操作數(shù)的求值結果為 true,就不會對第二個操作數(shù)求值了。
! 邏輯非
邏輯非操作可以應用于任何類型的操作數(shù),無論這個值是什么數(shù)據(jù)類型,這個運算符都會返回一個布爾值。邏輯非運算符首先會將它的操作數(shù)轉換為一個布爾值,然后再對其求反。邏輯非運算符遵循下列規(guī)則:
- 如果操作數(shù)是一個對象,返回
false; - 如果操作數(shù)是一個空字符串,返回
true; - 如果操作數(shù)是一個非空字符串,返回
false; - 如果操作數(shù)是數(shù)值
0,返回true; - 如果操作數(shù)是任意非
0數(shù)值(包括Infinity),返回false; - 如果操作數(shù)是
null,返回true; - 如果操作數(shù)是
NaN,返回true; - 如果操作數(shù)是
undefined,返回true。
下面幾個例子展示了應用上述規(guī)則的結果:
console.log(!false); // true
console.log(!"blue"); // false
console.log(!0); // true
console.log(!NaN); // true
console.log(!""); // true
console.log(!12345); // false
邏輯非運算符也可以用于將一個值轉換為與其對應的布爾值。而同時使用兩個邏輯非運算符,實際上就會模擬 Boolean() 轉型函數(shù)的行為。其中,第一個邏輯非操作會基于無論什么操作數(shù)返回一個布爾值,而第二個邏輯非操作則對該布爾值求反,于是就得到了這個值真正對應的布爾值。當然,最終結果與對這個值使用 Boolean() 函數(shù)相同,例如:
console.log(!!"blue"); //true
console.log(!!0); //false
console.log(!!NaN); //false
console.log(!!""); //false
console.log(!!12345); //true
位運算符
在 JavaScript 中,當對數(shù)值應用位運算符時,后臺會發(fā)生如下轉換過程:64位的數(shù)值被轉換成32位數(shù)值,然后執(zhí)行位操作,最后再將32位的結果轉換回64位數(shù)值。這個轉換過程導致了一個嚴重的副效應,即在對特殊的 NaN 和 Infinity 值應用位操作時,這兩個值都會被當成 0 來處理。如果對非數(shù)值應用位運算符,會先使用 Number() 函數(shù)將該值轉換為一個數(shù)值,然后再應用位操作,得到的結果將是一個數(shù)值。
~ 按位非
簡單的理解,對任一數(shù)值 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
& 按位與
按位與操作就是將兩個數(shù)值的每一位對齊,兩個數(shù)值的對應位都是 1 時才返回 1,任何一位是 0,結果都是 0。如下表所示:
| 第一個數(shù)值的位 | 第二個數(shù)值的位 | 結果 |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | 0 | 0 |
| 按位或
按位或操作就是將兩個數(shù)值的每一位對齊,兩個數(shù)值只要有一個位是 1 就返回 1,只在兩個位都是 0 的情況下才返回 0。如下表所示:
| 第一個數(shù)值的位 | 第二個數(shù)值的位 | 結果 |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |
^ 按位異或
按位異或與按位或的不同之處在于,兩個數(shù)值只有一個 1 時才返回 1,如果對應的兩位都是 1 或都是 0,則返回 0。
| 第一個數(shù)值的位 | 第二個數(shù)值的位 | 結果 |
|---|---|---|
| 1 | 1 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |
<< 左移
這個運算符會將數(shù)值的所有位向左移動指定的位數(shù)。例如:
var oldValue = 2; // 等于二進制的 10
var newValue = oldValue << 5; // 等于二進制的 1000000,十進制的 64
注意,左移不會影響操作數(shù)的符號位。換句話說,如果將 -2 向左移動 5 位,結果將是 -64,而非 64。
>> 有符號的右移
這個運算符會將數(shù)值向右移動,但保留符號位(即正負號標記)。
var oldValue = 64; // 等于二進制的 1000000
var newValue = oldValue >> 5; // 等于二進制的 10 ,即十進制的 2
>>> 無符號的右移
這個運算符會將數(shù)值的所有32位都向右移動。對正數(shù)來說,無符號右移的結果與有符號右移相同。
var oldValue = 64; // 等于二進制的 1000000
var newValue = oldValue >>> 5; // 等于二進制的 10 ,即十進制的 2
無符號右移運算符會把負數(shù)的二進制碼當成正數(shù)的二進制碼。而且,由于負數(shù)以其絕對值的二進制補碼形式表示,因此就會導致無符號右移后的結果非常之大。
var oldValue = -64; // 等于二進制的 11111111111111111111111111000000
var newValue = oldValue >>> 5; // 等于十進制的 134217726
賦值運算符
簡單的賦值運算符由等于號 = 表示,其作用就是把右側的值賦給左側的變量,如下面的例子所示:
var num = 10;
如果在等于號 = 前面再添加乘性運算符、加性運算符或位運算符,就可以完成復合賦值操作。這種復合賦值操作相當于是對下面常規(guī)表達式的簡寫形式:
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。雖然逗號的這種使用方式并不常見,但這個例子可以幫我們理解逗號的這種行為。
關卡
// 挑戰(zhàn)一
var x=1;
if(!!function f(){}){
x+=typeof f;
}
console.log(x); // ???
// 挑戰(zhàn)二
(function f(f){
console.log(typeof f()); // ???
})(function(){return 1;});
// 挑戰(zhàn)三
console.log(typeof 2*3); // ???
console.log(typeof 2+3); // ???
// 挑戰(zhàn)四
var a=0,b=0;
console.log(a+++b); // ???
console.log(a); // ???
console.log(b); // ???
// 挑戰(zhàn)五
var a,b,c;
a=b==c;
console.log(a); // ???
// 挑戰(zhàn)六
console.log(1 && 3); // ???
console.log(1 && "foo" || 0); // ???
console.log(1 || "foo" && 0); // ???
// 挑戰(zhàn)七
var a=1;
var b=(a=(2,4,6))+a++
console.log(b); // ???
// 挑戰(zhàn)八
if (!("a" in window)) {
var a = 1;
}
console.log(a); // ???
// 挑戰(zhàn)九
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing'); // ???
// 挑戰(zhàn)九
console.log(1 + - + + + - + 1);
更多
關注微信公眾號「劼哥舍」回復「答案」,獲取關卡詳解。
關注 https://github.com/stone0090/javascript-lessons,獲取最新動態(tài)。