寫 JavaScript 偶爾會踩到一些小地雷,會讓新手思考很久很久,這邊整理一份清單!
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
上下文中可以是 true
或 false
。空陣列是真值,這意味著它在“布林”上下文中被視為“真”。當我們對其應用 !
運算符時,它會轉換為 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 中的一個特殊值,代表一個 undefined
或 unrepresentable
數值。
當您將 typeof
與 NaN
一起使用時,它將返回 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
強制轉換為數字 1
,false
強制轉換為 0
。所以 1 > 5
是 false
,因為 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 函數的第二個參數是指定要使用的編號系統的基數。比方說:binary
、octal
、decimal
、hexadecimal
等。如果未指定基數,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
指的是該循環迭代中的值。
簡單分享,希望對您有幫助!