JavaScript中的 NaN 與 isNaN
NaN
NaN 即Not a Number,不是一個數字。 在 JavaScript 中,整數和浮點數都統稱為 Number 型別 。除此之外,Number 型別還有一個很特殊的值,即 NaN 。它是 Number物件上的一個靜態屬性,可以通過 Number.NaN 來訪問 。
console.log(Number.NaN); // NaN
在 ECMAScript v1 和其後的版本中,還可以用預定義的全域性屬性 NaN代替 Number.NaN 。
console.log(NaN); // NaN
在以下兩種場景中,可能會產生 NaN 值 。
【1】表示式計算
一個表示式中如果有減號 (-)、乘號 (*) 或 除號 (/) 等運算子時,JS 引擎在計算之前,會試圖將表示式的每個分項轉化為 Number型別(使用 Number(x) 做轉換)。如果轉換失敗,表示式將返回 NaN 。
100 - '2a' ; // NaN '100' / '20a'; // NaN '20a' * 5 ; // NaN undefined - 1; // NaN, Number(undefined) == NaN [] * 20 ; // 0, Number([]) == 0 null - 5; // -5, Number(null) == 0
而 加號 (+) 不會將其兩邊的變數轉化為 Number 型別,這是因為JS表示式的執行順序是按照運算子的優先順序從左到右依次進行的,如果加號 (+) 兩邊的變數都是 Number 型別時,才會做數字相加運算,如果其中有一個變數是字串,則會將兩邊都作為字串相加。
5 + 4 + '6' = '96'; 1 + '2' + 3 = '123'
【2】型別轉換
直接使用 parseInt,parseFloat 或 Number 將一個非數字的值轉化為數字時,表示式返回 NaN 。
'abc' - 3 // NaN parseInt('abc') // NaN parseFloat('abc') // NaN Number('abc') // NaN
對於數字+字元的值,其轉化結果會有所不同:
Number('123abc'); // NaN parseInt('123abc'); // 123 parseInt('123abc45'); // 123 parseFloat('123.45abc');// 123.45
Number 轉換的是整個值,而不是部分值;parseInt 和 parseFloat 只轉化第一個無效字元之前的字串。 另外,一元加操作符也可以實現與 Number 相同的作用。
+ '12abc'; // NaN + '123'; // 123 + '123.78'; // 123.78 + 'abc'; // NaN
因此,當一個字串不能被 Number、parseInt 或 parseFloat 成功轉換時,就返回 NaN,表示該字串無法被識別為數字型別,這是一個異常狀態,並不是一個確切的值。
isNaN
isNaN() 是一個全域性方法,它的作用是檢查一個值是否能被 Number()成功轉換 。 如果能轉換成功,就返回 false,否則返回 true 。
isNaN(NaN) // true 不能轉換 isNaN('123') // false 能轉換 isNaN('abc') // true 不能轉換 isNaN('123ab') // true 不能轉換 isNaN('123.45abc') // true 不能轉換
可以看出,isNaN() 沒有辦法判斷某個值本身是否為 NaN 。如果想要知道某個值本身是否為 NaN,可以利用NaN 不等於自身 這一特性來判斷。
function selfIsNaN(value){ return value !== value }
另外,ES6 在 Number 物件上也提供了 isNaN() 方法,和全域性方法 isNaN() 不同的是,它用於判斷某個值本身是否為 NaN,而不需要進行型別轉換。
Number.isNaN('123'); // false 本身不是NaN Number.isNaN('abc'); // false 本身不是NaN Number.isNaN(NaN); // true 本身是NaN