寫 JavaScript 偶爾會踩到一些小地雷,會讓新手思考很久很久,這邊整理一份清單!

原文出處:https://dev.to/codeofrelevancy/unexpected-moments-of-javascript-that-will-challenge-your-understanding-of-the-language-4834


1️⃣

2 == [2] // true

使用 == 做比較,可能會對變數型別做一些額外的轉換

在本例中,數字 2 被轉換為字串,陣列“[2]”也被轉換為字串。導致兩個值都是“2”。這就是為什麼比較結果為“真”。

通常建議使用 嚴格相等運算符 === 而不是 ==避免意外結果..

更多案例:

'123' == 123        // true 
'foo' == NaN        // false
undefined == null   // true 
NaN === NaN         // false
NaN == NaN          // false
0 == null           // false

2️⃣

[] == ![] // true

將空陣列“[]”與通過取反建立的“布林值”進行比較(使用 ! 運算符) 一個非空陣列 []。這種比較的結果是 true,乍一看似乎出乎意料。

在 JS 中,每個值在 boolean 上下文中可以是 truefalse。空陣列是真值,這意味著它在“布林”上下文中被視為“真”。當我們對其應用 ! 運算符時,它會轉換為 false

另一方面,通過否定非空陣列建立的“boolean”值為“false”。當我們使用 == 運算符,JS 執行類型約束,這意味著它會在比較它們之前嘗試將值轉換為通用類型。因此,空陣列被轉換為 false,結果兩邊都是 false。最後,比較返回“true”。

探索更多:

['a', 'b'] !== ['a', 'b']   // true
['a', 'b'] == ['a', 'b']    // false
[1, 2] + [3, 4]             // "1,23,4" 

3️⃣

null == undefined // true

double equals == operator 用於比較兩個值是否相等,同時忽略它們的資料類型。當使用雙等號運算符比較值“null”和“undefined”時,它們被認為是相等的,比較結果將為“true”。這是因為“null”和“undefined”都表示缺少值,並且在這種情況下彼此非常等價。

使用嚴格相等運算符:

null === undefined // false

4️⃣

typeof NaN   // number
typeof null  // object

在 JS 中,typeof 是一個運算符,用於確定值或變數的類型。

NaN 代表 Not a Number 是 JS 中的一個特殊值,代表一個 undefinedunrepresentable 數值。

當您將 typeofNaN 一起使用時,它將返回 number。這可能看起來很奇怪,但這是因為 NaN 在技術上是 JS 中的數字資料類型,儘管它代表的實際上不是數字。

當 typeof 應用於 null 時,它返回字串 object 。這是因為“null”被認為是一個表示空物件引用的特殊值。 null 本身不是一個物件,而是一個原始值。這被認為是 JS 語言設計中的一個怪癖。

探索更多:

typeof function(){}     // "function"
null instanceof Object  // false

5️⃣

true == "1"  // true
false == "0" // true

JS 將字串“1”轉換為“布林”值“true”,將字串“0”轉換為“false”,因為任何非空字串都被視為truthy,而在另一端則被視為falsy。因此,比較變成了 true == true 是 true 和 false == false 是 true 。

探索更多:

1 + true      // 2
1 - true      // 0
'' == false   // true
0 == false    // true
true + false  // 1

6️⃣

"1" + 1    // "11"
2 + "2"    // "22"
"5" - 3    // 2

當您將 + 運算符 與“字串”和“數字”一起使用時,數字會被轉換到一個字串並連接到該字串。

如果可以將“字串”解析為“數字”,它將減去“數字”來自“字串”。

所以,

"1" + 1 變成字串 "11"

2 + "2" 變成字串 "22"

"5" - 3 變成數字 2

探索更多:

+"1"                  // 1
-"1"                  // -1

+true                 // 1
-true                 // -1

+false                // 0
-false                // -0

+null                 // 0
+undefined            // NaN

1 / "2"               // 0.5
"2" / 1               // 2

1 / 0                 // Infinity
-1 / 0                // -Infinity

3 * "abc"             // NaN

true > false          // true  

undefined + 1         // NaN
undefined - 1         // NaN
undefined - undefined // NaN
undefined + undefined // NaN

null + 1              // 1
null - 1              // -1
null - null           // 0
null + null           // 0

Infinity + 1          // Infinity
Infinity - 1          // Infinity
Infinity - Infinity   // NaN
Infinity + Infinity   // Infinity
Infinity / Infinity   // NaN

7️⃣

"b" + "a" + + "a" + "a" // "baNaNa"

它連接字串 b、字串 a、由表達式 +"a" 和字串 a 產生的字串。

+"a" 將字串 a 強制轉換為計算結果為 NaN(不是數字)的數字,因為 a 不是有效數字。

當我們連接“b”、“a”、“NaN”(表示為空字串)和“a”時,我們得到字串“baNaNa”。


8️⃣

!{}       // false
{} == !{} // false
{} == {}  // false

當我們將一個空物件“{}”與一個否定的空物件“!{}”進行比較時。驚嘆號 ! 是一個邏輯運算符,它否定物件的值,所以 !{} 返回 false 因為對像在 JS 中被認為是真實的。我們實際上是在將 {}false 進行比較,結果是 false 值,因為它們在值或資料類型上不相等。

在最後一個表達式中,我們正在比較兩個空物件“{}”。儘管它們可能看起來相同,但它們是兩個獨立的物件,在內存中具有不同的引用,因此它們在值或資料類型上並不相等。最後,比較也會產生一個“假”值。

當您在用大括號{} 包裹的兩個物件之間使用plus operator + 時,它嘗試將物件連接為字串。

探索更多:

{} + [] === ""  // false
!!{}            // true 
!![]            // true 
[] + []         // ""
[] + {}         // "[object Object]"
{} + []         // "[object Object]"
{} + {}         // "[object Object][object Object]"
[] == false     // true
!!''            // false
!!0             // false
!!null          // false
!!undefined     // false 

9️⃣

7 > 6 > 5 // false

首先,“7 > 6”的計算結果為“真”,因為 7 大於 6。

接下來,評估“true > 5”。在 JS 中,true 強制轉換為數字 1false 強制轉換為 0。所以 1 > 5false,因為 1 不大於 5

所以最後,7 > 6 > 5 等價於 true > 5,即 false

探索更多:

5 < 6 < 7  // true
0 > null   // false

1️⃣0️⃣

Math.max() // -Infinity
Math.min() // Infinity

Math.max()Math.min() 是可用於分別查找一組數字中的最大值和最小值的函數。

當不帶任何參數呼叫時,Math.max() 返回 -Infinity,它表示 JS 中可能的最小 number,另一方面,Math.min() 返回 Infinity,它表示可能的最大 JS 中的數字

這種行為是有道理的,因為如果沒有提供數字,則 Math.max() 沒有要返回的最大數字,同樣,沒有為 Math.min() 返回的最小數字


1️⃣1️⃣

parseInt('08')       // 8
parseInt('08', 10)   // 8 
parseInt('0x10')     // 16 

parseInt('08') 將字串 08 轉換為整數 8。如果您要編寫“parseInt('08', 10)”,該函數仍將返回“8”。

這背後的原因是因為 parseInt 函數的第二個參數是指定要使用的編號系統的基數。比方說:binaryoctaldecimalhexadecimal 等。如果未指定基數,parseInt 將嘗試根據字串格式檢測基數。在上面的例子中,“08”被認為是一個八進制數,因為它以“0”開頭,所以它被轉換為十進制數“8”。

parseInt('0x10')hexadecimal 字串 0x10 轉換為整數 16。基數也未指定,但前綴“0x”表示該數字應被視為“十六進制”數字,因此它被轉換為“16”作為十進制數。

探索更多:

parseFloat('3.14.15')  // 3.14 
parseFloat('0.0')      // 0 

1️⃣2️⃣

(function(x) { delete x; return x; })(1);   // 1

採用參數“x”的匿名函數。在函數內部,它試圖刪除 x 變數,但這是不可能的,因為 x 是函數參數,無法刪除。然後該函數返回 x 的值。

當使用參數“1”呼叫此函數時,函數內部的“x”值將設置為“1”。在這種情況下,刪除操作沒有效果,函數只是返回 x 的值,即 1


1️⃣3️⃣

for (var i = 0; i < 3; ++i) {
  setTimeout(() => console.log(i), 1000); // returns 3 three times
}

for (let i = 0; i < 3; ++i) {
  setTimeout(() => console.log(i), 1000); // returns 0 1 2
}

這是因為 var 在函數範圍內建立了一個綁定,所以在一秒超時後循環已經執行完了,因此你得到了 3 次 3。通過使用 let,您可以在塊作用域(循環)綁定變數,因此它返回您期望的值,因為 i 指的是該循環迭代中的值。


簡單分享,希望對您有幫助!

按讚的人:

共有 0 則留言