關於NaN

昨天看到一個面試題:怎樣實現 isNaN() 方法?html

細細研究了一下 NaN,發現這個東西不經常使用,坑卻異常多,很有 「茴」 字有幾種寫法的感受,這裏記錄下總結的東西吧。面試

NaN 是什麼

NaNNot a Number(非數值),但它是一個特殊的數值,因此:數組

typeof(NaN)  // "number"

編碼時不多直接使用 NaN,一般是在計算失敗時,做爲 Math 的某個方法的返回值出現的。編碼

它有兩個重要的性質:code

  • NaN與任何值都不相等,包括NaN自身:
alert(NaN == NaN)  // false
alert(NaN === NaN)  // false
  • 任何涉及 NaN的操做都會返回NaN

哪些狀況會產生NaN?

1. 計算

JS 在進行加減乘除運算以前,會先調用 Number()方法,將非數值的運算項轉化爲數值,若是轉換失敗就返回NaN,好比:htm

1-'a';   // NaN

首先是執行Number('a'),不能成功轉化爲數值,返回NaN,再利用NaN的第二條性質:任何涉及 NaN的操做都會返回NaN,因此最終的結果是NaN對象

2. 類型轉換

當一個值不能被NumberparseIntparseFloat成功轉換爲數值,就返回NaN,舉例:blog

Number('123.456abc');   // NaN
parseInt('123.456abc');  // 123
parseFloat('123.456abc'); // 123.456

Number('abc');  // NaN
parseInt('abc');  // NaN
parseFloat('abc');  // NaN

Number([]);  // 0
parseInt([]);  // NaN
parseFloat([]);  // NaN

Number('');  // 0
parseInt('');  // NaN
parseFloat('');  // NaN

Number({});  // NaN
parseInt({});  // NaN
parseFloat({});  // NaN

這裏要注意三者之間的差別,個人理解是 parseIntparseFloat會盡可能將參數值轉化爲數值。ip

關於isNaN()

isNaNwindow對象的一個方法,比較詭異的是:isNaN(x)並非判斷參數x自己是否是NaN,而是判斷Number(x)是否是NaN。也就是說先用Number()去轉化參數,再去判斷轉化的結果。返回的結果是一個布爾值。字符串

isNaN(NaN);  // true
isNaN(123);  // false
isNaN('abc');  //true
isNaN('123abc'); //true

isNaN({});  // true,由於Number({})=NaN
isNaN('');  // false, 由於Number('')=0
isNaN([]);  // false,由於Number([])=0

能夠看到最後, 空字符串'' 和 空數組[]顯然是非數值,而isNaN返回了false,緣由就是Number轉換在做怪,這點仍是很詭異的...因此我選擇慎用...

那麼isNaN是怎麼實現的呢,原理就是利用NaN的第一條性質:NaN與任何值都不相等,包括NaN自身。

var isNaNA = function(value) {
    var n = Number(value);
    return n !== n;
};

先用Number()轉換參數,再判斷轉換後的結果是否是不等於自身。

MDN 上給的實現方式是這樣的:

var isNaNB = function(value) {
    var n = parseInt(value);
    return n !== n;
};

我以爲是有問題的,由於:

isNaN('123abc');    // true
isNaNA('123abc');   // true
isNaNB('123abc');   // false

Number.isNaN()

ES6 中的Number.isNaN()是一個判斷NaN的升級版,和isNaN()不一樣的是,Number.isNaN()不會強制轉化參數,直接對參數自己作判斷,這樣只有參數顯示等於NaN,纔會返回true

Number.isNaN(NaN);  // true,其餘狀況都返回 false

它的實現原理是:

function isNaNC (value) {
    return typeof(value) === "number" && isNaN(value);
}

算了,仍是不糾結了....

參考

MDN isNaN()
JavaScript中的 NaN 與 isNaN

相關文章
相關標籤/搜索