當前位置: 妍妍網 > 碼農

JavaScript 奇葩行為大賞

2024-06-07碼農

本文來分享一些 JavaScript 中離譜的設計,這些設計日常開發遇到的機率可能比較小,但面試可能會問到噢!

parseInt(0.0000005)

答案:5

parseInt(0.5);// -> 0
parseInt(0.05);// -> 0
parseInt(0.005);// -> 0
parseInt(0.0005);// -> 0
parseInt(0.00005);// -> 0
parseInt(0.000005);// -> 0
parseInt(0.0000005);// -> 5

parseInt 函式將其第一個參數轉換為字串(如果它還不是字串),然後再轉換為數位。當將 0.0000005 轉換為字串時,會得到以下結果:

String(0.0000005);// -> "5e-7"

然後 parseInt 函式只取該字串的第一個字元,即 5,並將其解析為一個數位。

[] == ![]

答案: true

[] == ![] 之所以返回 true ,是因為比較過程中發生了隱式的型別轉換。下面來逐步解析:

  1. [] 是一個空陣列,它是真值。 ![] false ,因為當將空陣列強制轉換為布爾值時,它變為 true ,然後被否定為 false 。因此,比較變成了 [] == false

  2. 當比較不同型別時,JavaScript 將嘗試將一個或兩個值強制轉換為相同型別。在這種情況下,它將嘗試將陣列強制轉換為原始值。

  3. 一個空陣列,當被強制轉換為原始值時,變成了一個空字串 "" 。因此,運算式 [] == false 實際上變成了 "" == false

  4. 現在,JavaScript 嘗試將布爾值 false 轉換為數位,即 0 ,運算式就變成了 "" == 0

  5. 根據 JavaScript 的規則,當比較一個字串和一個數位時,字串將被強制轉換為數位。因此, "" 被強制轉換為數位後變成了 0 。這時比較的就是 0 == 0 ,結果是 true

NaN === NaN

答案: false

在 JavaScript 中,NaN(Not a Number)是一個特殊的值,表示一個非數位的值。然而,當使用 ===(嚴格相等運算子)來比較 NaN 時,會出現一個特殊的情況:NaN 並不等於 NaN。具體來說,NaN === NaN 的結果是 false,盡管兩者都是 NaN。這是因為在 IEEE 754 浮點數標準中,NaN 被定義為不等於任何其他值,包括它自身。

要檢查一個值是否是 NaN,通常使用 isNaN() 函式,但請註意,isNaN() 對於非數位型別的參數(如字串或物件)也可能返回 true,因為它會嘗試將這些參數轉換為數位。更嚴格的檢查方法是使用 Number.isNaN(),它只有在參數確實是 NaN 時才返回 true。

NaN===NaN// false
isNaN(NaN);// true,但這不是最佳方式
Number.isNaN(NaN);// true,這是更好的方式

[1, 2] + [3, 4]

答案: "1,23,4"

在 JavaScript 中,當嘗試使用 + 運算子來連線兩個陣列,實際上並不會執行陣列的拼接或合並。相反,由於 + 運算子在 JavaScript 中既可以用作加法運算子(對於數位),也可以用作字串連線運算子(對於字串),因此陣列會首先被轉換為字串,然後再進行連線。

陣列到字串的轉換是透過呼叫陣列的 toString() 方法實作的,這通常會生成一個由陣列元素組成的逗號分隔的字串。因此, [1, 2] 會被轉換為 "1,2" ,而 [3, 4] 會被轉換為 "3,4" 。然後,這兩個字串會被 + 運算子連線起來,得到 "1,23,4" 。所以, [1, 2] + [3, 4] 的結果是 "1,23,4"

如果想要合並兩個陣列,應該使用陣列的 concat() 方法或擴充套件運算子如下所示:

  • 使用 concat() 方法:

  • const result =[1,2].concat([3,4]);// [1, 2, 3, 4]

  • 使用擴充套件運算子:

  • const result =[...[1,2],...[3,4]];// [1, 2, 3, 4]

    typeof null

    答案: object

    在 JavaScript 早期版本中,所有值都儲存在 32 位的單元中,每個單元包含一個小的 型別標簽(1-3 bits) 以及當前要儲存的數據。型別標簽共有五種型別:

    000: object - 數據型別為 物件。
    1: int - 數據型別為 有符號整數。
    010: double - 數據型別為 雙精度的浮點數。
    100: string - 數據型別為 字串。
    110: boolean - 數據型別為 布爾值。

    null 的值是機器碼 NULL 指標(指標值是 000 ),也就是說 null 的型別標簽也是 000 ,和 object 的型別標簽一樣,所以會被判定為 object

    try...finally

    答案:2

    (()=>{
    try{
    return1;
    }finally{
    return2;
    }
    })();

    在JavaScript中,當在一個函式(包括箭頭函式)的 try 塊和 finally 塊中都有 return 語句時, finally 塊中的 return 語句會覆蓋 try 塊中的 return 語句。這是因為 finally 塊總是會被執行,無論 try 塊中的程式碼是否成功執行,或者是否丟擲了異常。而且,如果 finally 塊中有 return 語句,那麽這個 return 語句將決定整個函式的返回值。

    0.14 * 100

    答案:14.000000000000002

    0.13*100// 13
    0.14*100// 14.000000000000002
    0.15*100// 15
    0.16*100// 16

    在JavaScript中,所有的數位都是以 64 位浮點數形式儲存的,即使它們被聲明為整數。由於二進制無法精確表示所有的十進制小數,因此在進行浮點數運算時,可能會出現精度問題。由於在二進制浮點數表示中,0.14 不能精確表示,因此在進行乘法運算時會出現微小的舍入誤差。一個經典的問題就是 0.1 + 0.2 不等於 0.3。這兩個問題出現的原因是一樣的。

    0.1+0.2===0.3// false
    0.1+0.5===0.6// true

    為了處理這種精度問題,可以使用 Number.EPSILON Math.round toFixed 等方法來比較浮點數或將其格式化為固定小數位數。如果需要精確計算,並且不能容忍這種舍入誤差,可以使用特殊的庫,如 decimal.js bignumber.js ,它們提供了高精度的十進制數運算。

    1.toString()

    答案:報錯

    const num =1;
    num.toString()// 1
    1.toString();// Uncaught SyntaxError: Invalid or unexpected token
    1..toString();// 1

    在 JavaScript 中, 1.toString() 會導致一個語法錯誤,因為點號( . )在這裏被解析為浮點數的一部份,但緊接著並沒有另一個數位來形成有效的浮點數位面量,所以解析器會丟擲一個 Uncaught SyntaxError: Invalid or unexpected token 錯誤。

    然而,當寫 1..toString() 時,情況就不同了。這裏有兩個點號,但第一個點號實際上並不是浮點數的一部份。這是因為 JavaScript 的解析器在遇到連續的點號時會將它們視為一種特殊的語法結構,即第一個點號被視為數位 1 的結尾(盡管在這裏它並沒有實際意義,因為 1 已經是完整的數位),而第二個點號則作為存取物件內容的操作符。

    因此, 1..toString() 實際上是這樣被解析的:

    1. 數位 1 被解析為一個完整的數位字面量。

    2. 由於緊接著有一個點號,但它並沒有跟隨另一個數位來形成浮點數,所以它被解釋為物件內容的存取操作符。

    3. 因為 1 在 JavaScript 中是一個原始值,它本身並沒有 .toString() 方法,但是在這裏,由於點號操作符的存在,JavaScript 會嘗試將 1 轉換為一個 Number 物件(這是一個稱為裝箱或自動封裝的過程)。

    4. 一旦 1 被轉換為 Number 物件,就可以呼叫它的 .toString() 方法了。

    所以, 1..toString() 最終會返回字串 "1",盡管這種寫法在實際編程中並不常見,因為它可能會引起混淆。更常見的做法是直接對數位變量使用 .toString() 方法,也就是上面的第一種寫法。

    Math.max() < Math.min()

    答案: true

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

    在標準的 JavaScript 環境中, Math.max() 在沒有參數時應該返回 -Infinity ,而 Math.min() 在沒有參數時應該返回 Infinity 。但是,由於 Infinity 總是大於 -Infinity ,所以 Math.max() < Math.min() 返回 true。

    9007199254740992 === 9007199254740993

    答案: true JavaScript 的 Number 型別是基於 IEEE 754 標準 (也稱為 64 位浮點數)實作的,這意味著它有一些限制,特別是關於可以精確表示的數位的範圍和精度。在 IEEE 754 標準中,最大的安全整數(即可以精確表示的最大整數)是 Number.MAX_SAFE_INTEGER ,其值為 9007199254740991 (2 的 53 次方減 1)。

    當嘗試使用大於 Number.MAX_SAFE_INTEGER 的整數時,JavaScript 會嘗試將其儲存為一個近似的浮點數,這可能會導致精度損失。在這個例子中, 9007199254740992 9007199254740993 都會被轉換為近似的浮點數,但由於精度限制,這兩個數位可能會表示為相同的浮點數值。

    因此,如果需要在 JavaScript 中表示大數位時,建議使用字串來儲存大數,以避免精度遺失。

    往期推薦