《JavaScript 闖關記》之表示式和運算子

劼哥stone發表於2016-10-27

表示式

表示式是由數字、運算子、數字分組符號(如括號)、自由變數和約束變數等以能求得數值的有意義排列方法所得的組合。JavaScript 表示式主要有以下幾種形式:

  • 原始表示式:常量、變數、保留字。
  • 物件、陣列初始化表示式:var obj={a:1,b:2};var arr=[1,2,3];
  • 函式定義表示式:var fn=function(){}
  • 屬性訪問表示式:Math.abs
  • 呼叫表示式:alert('hello');
  • 物件建立表示式:new object();

運算子

JavaScript 中的運算子用於算術表示式、比較表示式、邏輯表示式、賦值表示式等。需要注意的是,大多數運算子都是由標點符號表示的,比如 +=。而另外一些運算子則是由關鍵字表示的,比如 typeofinstanceof,關鍵字運算子和標點符號都是正規的運算子。

下表列出了 JavaScript 中所有的運算子,並按照運算子的優先順序排序的,前面的運算子優先順序要高於後面的運算子優先順序,被空行分隔開來的運算子具有不同的優先順序。標題為 A 的列表示運算子的結合性(Associativity),L 表示從左至右、R 表示從右至左,標題為 N 的列表示運算元的個數(Number)。

運算子 操作 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

因為 | 是製表符,會導致格式混亂,所以表格中的 | 均以 代替。

一元運算子

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。例如:

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 運算子」

++ -- 運算子

++ -- 遞增遞減運算子借鑑自 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

* 乘法運算子

用於計算兩個數值的乘積,在處理特殊值的情況下,乘法運算子遵循下列特殊的規則:

  • 如果運算元都是數值,執行常規的乘法計算,即兩個正數或兩個負數相乘的結果還是正數,而如果只有一個運算元有符號,那麼結果就是負數。如果乘積超過了 JavaScript 數值的表示範圍,則返回 Infinity-Infinity
  • 如果有一個運算元是 NaN,則結果是 NaN
  • 如果是 Infinity0 相乘,則結果是 NaN
  • 如果是 Infinity 與非 0 數值相乘,則結果是 Infinity-Infinity,取決於有符號運算元的符號;
  • 如果是 InfinityInfinity 相乘,則結果是 Infinity
    如果有一個運算元不是數值,則在後臺呼叫 Number()將其轉換為數值,然後再應用上面的規則。

/ 除法運算子

用於計算兩個數值的商,與乘法運算子類似,除法運算子對特殊的值也有特殊的處理規則。這些規則如下:

  • 如果運算元都是數值,執行常規的除法計算,即兩個正數或兩個負數相除的結果還是正數,而如果只有一個運算元有符號,那麼結果就是負數。如果商超過了 JavaScript 數值的表示範圍,則返回 Infinity-Infinity
  • 如果有一個運算元是 NaN,則結果是 NaN
  • 如果是 InfinityInfinity 除,則結果是 NaN
  • 如果是零被零除,則結果是 NaN
  • 如果是非零的有限數被零除,則結果是 Infinity-Infinity,取決於有符號運算元的符號;
  • 如果是 Infinity 被任何非零數值除,則結果是 Infinity-Infinity,取決於有符號運算元的符號;
  • 如果有一個運算元不是數值,則在後臺呼叫 Number() 將其轉換為數值,然後再應用上面的規則。

% 求模運算子

用於計算兩個數值的餘數,與另外兩個乘性運算子類似,求模運算子會遵循下列特殊規則來處理特殊的值:

  • 如果運算元都是數值,執行常規的除法計算,返回除得的餘數;
  • 如果被除數是無窮大值而除數是有限大的數值,則結果是 NaN
  • 如果被除數是有限大的數值而除數是零,則結果是 NaN
  • 如果是 InfinityInfinity 除,則結果是 NaN
  • 如果被除數是有限大的數值而除數是無窮大的數值,則結果是被除數;
  • 如果被除數是零,則結果是零;
  • 如果有一個運算元不是數值,則在後臺呼叫 Number() 將其轉換為數值,然後再應用上面的規則。

加性運算子

加法和減法這兩個加性運算子應該說是程式語言中最簡單的算術運算子了。但是在 JavaScript 中,這兩個運算子卻都有一系列的特殊行為。與乘性運算子類似,加性運算子也會在後臺轉換不同的資料型別。然而,對於加性運算子而言,相應的轉換規則還稍微有點複雜。

+ 加法運算子

如果兩個運算子都是數值,執行常規的加法計算,然後根據下列規則返回結果:

  • 如果有一個運算元是 NaN,則結果是 NaN
  • 如果是 InfinityInfinity,則結果是 Infinity
  • 如果是 -Infinity-Infinity,則結果是 -Infinity
  • 如果是 Infinity 加- Infinity,則結果是 NaN
  • 如果是 +0+0,則結果是 +0
  • 如果是 -0-0,則結果是 -0
  • 如果是 +0-0,則結果是 +0;

如果有一個運算元不是數值,那麼就要應用如下規則:

  • 如果兩個運算元都是字串,則將第二個運算元與第一個運算元拼接起來;
  • 如果只有一個運算元是字串,則將另一個運算元轉換為字串,然後再將兩個字串拼接起來。
  • 如果有一個運算元是物件、數值或布林值,則呼叫它們的 toString() 方法取得相應的字串值,然後再應用前面關於字串的規則。對於 undefinednull,則分別呼叫 String() 函式並取得字串 "undefined""null"
  • 如果是 nullnull,則結果是 0;
  • 如果是 undefinedundefined,則結果是 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
  • 如果是 InfinityInfinity,則結果是 NaN
  • 如果是 -Infinity-Infinity,則結果是 NaN
  • 如果是 Infinity-Infinity,則結果是 Infinity
  • 如果是 -InfinityInfinity,則結果是 -Infinity
  • 如果是 +0+0,則結果是 +0
  • 如果是 +0-0,則結果是 -0
  • 如果是 -0-0,則結果是 +0

如果有一個運算元不是數值,那麼就要應用如下規則:

  • 如果有一個運算元是字串、布林值、nullundefined,則先在後臺呼叫 Number() 函式將其轉換為數值,然後再根據前面的規則執行減法計算。如果轉換的結果是 NaN,則減法的結果就是 NaN
  • 如果有一個運算元是物件,則呼叫物件的 valueOf() 方法以取得表示該物件的數值。如果得到的值是 NaN,則減法的結果就是 NaN。如果物件沒有 valueOf() 方法,則呼叫其 toString()方法並將得到的字串轉換為數值。
  • 如果是 nullnull,則結果是 0;
  • 如果是 undefinedundefined,則結果是 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() 方法,用得到的基本型別值按照前面的規則進行比較;
  • nullundefined 是相等的。
    要比較相等性之前,不能將 nullundefined 轉換成其他任何值。
  • 如果有一個運算元是 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位數值。這個轉換過程導致了一個嚴重的副效應,即在對特殊的 NaNInfinity 值應用位操作時,這兩個值都會被當成 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…,獲取最新動態。

相關文章