一、NaN
NaN,即 not a number,從字面意思上可以理解為非數(shù)字,但是在 JavaScript 的數(shù)據(jù)類(lèi)型劃分的時(shí)候,我們還是將其劃分進(jìn) number 類(lèi)型:
typeof NaN; // "number"
實(shí)際上,它是在算術(shù)運(yùn)算過(guò)程中,在原本期望得到一個(gè)數(shù)字類(lèi)型數(shù)據(jù)的地方,卻沒(méi)有辦法得出數(shù)字類(lèi)型的結(jié)果的時(shí)候,其它類(lèi)型編程語(yǔ)言可能將拋出異常,而 JavaScript 將得到一個(gè) NaN:
1 - 'a'; // NaN
1 / 'a'; // NaN
1 - {}; // NaN
1 + NaN; // NaN
1 * {}; // NaN
但需要注意一些特殊情況:
- JavaScript 中,+ 既是加法運(yùn)算符,又是字符串連接符(當(dāng)操作數(shù)中含有字符串時(shí),認(rèn)為是字符串連接操作)
1 + 'a'; // '1a'
'1' + 1; // '11'
- 當(dāng)分母為 0 的時(shí)候,將得到特殊的 Infinity 和 - Infinity
1 / 0; // Infinity
1 / (-0); // -Infinity
- 操作數(shù)可能被隱式轉(zhuǎn)換
1 + {}; // "1[object Object]"
1 + new Date('2019-09-01');
// "1Sun Sep 01 2019 08:00:00 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)"
1 + [1, 2]; // '11,2'
二 、判斷是否為 NaN
在 JavaScript NaN 有一個(gè)其它類(lèi)型數(shù)據(jù)都不具備的特性,這個(gè)數(shù)據(jù)與它本身不相等:
NaN == NaN; // false
NaN === NaN; // false
所以,我們可以基于這一點(diǎn),來(lái)判斷一個(gè)數(shù)據(jù)是否是 NaN:
function ifNaN(data) {
return data !== data;
}
ifNaN(NaN); // true
ifNaN(1); // false
三、原生的 isNaN 方法
第一感覺(jué),isNaN 方法應(yīng)該和我們前面實(shí)現(xiàn)的 ifNaN 效果一樣,但實(shí)際上二者區(qū)別卻很大:
isNaN(null); // false
isNaN(undefined); // true
isNaN(1); // false
isNaN({}); // true
isNaN('123'); // false
isNaN('0xa'); // false
isNaN 的定位跟之前的 ifNaN 不太一樣,ifNaN 是確定一個(gè)數(shù)據(jù)是否是 NaN,是 NaN 就返回 true,否則返回 false;isNaN 是確定一個(gè)數(shù)據(jù)在與其它數(shù)字類(lèi)型數(shù)據(jù)進(jìn)行算術(shù)運(yùn)算之后,是否可能得出 NaN:
null - 1; // -1
undefined - 1; // NaN
1 - 1; // 0
{} - 1; // NaN
'123' - 1; // 121
'0xa' - 1; // 9
這一點(diǎn)上,其實(shí)與上面 isNaN 的行為保持一致了。
在調(diào)用 isNaN 時(shí),如果傳入的參數(shù)不是 number 類(lèi)型,則會(huì)嘗試隱式轉(zhuǎn)換成 number 類(lèi)型的數(shù)據(jù),所以, isNaN(xxx) 其實(shí)與 isNaN(Nunber(xxx)) 等價(jià),所以上面 isNaN 的行為也就解釋得通了。
注:最初版本的 isNaN 是定義在全局對(duì)象 window(瀏覽器環(huán)境) / global(nodejs) 對(duì)象上的,但是 ES6 在 Number 構(gòu)造函數(shù)上添加了一個(gè)靜態(tài)方法 Number.isNaN,其效果與之前的 ifNaN 保持一致了。