有一次项目中发现原来isNaN和Number.isNaN是有着不一样的判断结果。记录一下避免下次踩坑。
要了解他们的区别,首先得明确NaN到底是什么?
在MDN的官方解释中
The global NaN property is a value representing Not-A-Number.
NaN是一个全局代表“Not-A-Number”的值。这样的解释个人觉得还是有些模糊。
在You-Dont-Know-JS中给出了更详细的解释:
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'。
那么结合"invalid number"、"failed number"、"bad number"等描述说明NaN首先得是一个Number类型的值,其次再判断是不是“not a number”。
目前的结论:”not-a-number“的类型是number,这还是有点令人困惑。我们来看下的You-Dont-Know-JS中的场景描述:(怕翻译产生歧义还是直接贴了原文)
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呢?
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是会报错的哦。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。