有一次项目中发现原来isNaN和Number.isNaN是有着不同的判断结果。记录一下避免下次踩坑。es6
要了解他们的区别,首先得明确NaN究竟是什么?this
在MDN的官方解释中翻译
The global NaN property is a value representing Not-A-Number.
NaN是一个全局表明“Not-A-Number”的值。这样的解释我的以为仍是有些模糊。eslint
在You-Dont-Know-JS中给出了更详细的解释:code
NaN literally stands for "not a number", though this label/description is very poor and misleading, as we'll see shortly. It would be much more accurate to think of NaN as being "invalid number," "failed number," or even "bad number," than to think of it as "not a number."
你们应该也知道:typeof NaN === 'number'。
orm
那么结合"invalid number"、"failed number"、"bad number"等描述说明NaN首先得是一个Number类型的值,其次再判断是否是“not a number”。ip
目前的结论:”not-a-number“的类型是number,这仍是有点使人困惑。咱们来看下的You-Dont-Know-JS中的场景描述:(怕翻译产生歧义仍是直接贴了原文)ci
NaN is a kind of "sentinel value" (an otherwise normal value that's assigned a special meaning) that represents a special kind of error condition within the number set. The error condition is, in essence: "I tried to perform a mathematic operation but failed, so here's the failed number result instead."
再来看一个例子:字符串
var a = 2 / "foo"; // NaN typeof a === "number"; // true
看到这里相信你们对NaN已经有了较为完整的认识。那么咱们如何来判断计算产生的结果是NaN呢?it
JS原生提供了isNaN的方法,拿上面的例子来举例:
var a = 2 / "foo"; isNaN(a) // true;
看似没什么问题,但其实isNaN是有着致命的缺陷。它把对NaN的判断就如同字面意思所写的那样:test if the thing passed in is either not a number or is a number。但从咱们上述对NaN的理解来看,这样的判断显然不正确。
例如:
var a = 2 / "foo"; var b = "foo"; a; // NaN b; // "foo" window.isNaN( a ); // true window.isNaN( b ); // true
b显然是一个字符串,从咱们以前对NaN的定义(NaN的类型是number)来看,b明显不该该是NaN。这个Bug由来许久,因此在es6中提供了替代方案Number.isNaN
。咱们来看下polyfill就知道他修复了什么问题。
if (!Number.isNaN) { Number.isNaN = function(n) { return ( typeof n === 'number' && window.isNaN(n) ); }; }
再试验下刚才的例子:
var a = 2 / "foo"; var b = "foo" Number.isNaN(a); // true Number.isNaN(b); // false
就能得出咱们理想的结果了。
还有一种polyfill很是简单,利用了NaN不等于他自身的特性,NaN是惟一有此特性的值,其余值都等于它们自身(包括undefined和null):
if (!Number.isNaN) { Number.isNaN = function(n) { return n !== n; }; }
最后就是建议你们都使用Number.isNaN来进行判断,若是用了eslint的话,那只写isNaN是会报错的哦。