-
Notifications
You must be signed in to change notification settings - Fork 642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
你可能不知道的 NaN 以及 underscore 1.8.3 _.isNaN 的一个 BUG #13
Comments
然后补充一下ES规范中,关于NaN的部分。这个才是最权威的。哈哈。 关于isNaN函数 从规范可看到,调用这个函数先会执行 英语渣,暂没有找到中文版的ES6规范。想看看ES6中关于 |
在lodash3.10.1版本中,.isNaN(new Number(0))会返回false,.isNaN(new Number(NaN))会返回true,这应该是解决了bug的结果吧? |
@juemin90 返回是正确的,不过 lodash 不熟,以前有 bug? |
_.isNaN(new Number(0)) 应该返回 false. 现在修复了,见 issue jashkenas/underscore#2257 |
哈哈哈哈,找到原因了。若是使用 var a = new Number(1);
a; /** => Number {[[PrimitiveValue]]: 1} */
+a; /** => 1 */
a !== +a; /** => true */
|
ES6 的 |
这篇文章并不在我的 underscore 源码解读计划中,直到 @pod4g 同学回复了我的 issue(详见 https://github.com/hanzichi/underscore-analysis/issues/2#issuecomment-227361035)。其实之前也有同学提出 isNaN 有 native 的 function,正好借此文辨析下几个常见的概念、方法,她们是 NaN,Number.NaN,isNaN,Number.isNaN,以及 underscore 中的 _.isNaN,顺便揪出了一个 BUG。
顺便安利,完整的 underscore 源码解读系列文章请戳 https://github.com/hanzichi/underscore-analysis
NaN & Number.NaN
ok,首先来了解下 NaN 和 Number.NaN 两个属性。
全局属性 NaN 表示 Not-A-Number 的值,顾名思义,就是表示 不是一个数字。
在编码中很少直接使用到 NaN。通常都是在计算失败时,作为 Math 的某个方法的返回值出现的(例如:Math.sqrt(-1))或者尝试将一个字符串解析成数字但失败了的时候(例如:parseInt("blabla"))。这样做的好处是,不会抛出错误,只需要在下一步的运算中判断上个步骤的运算结果是否是 NaN 即可。
接着来看 Number.NaN,这货和 NaN 完全一样。其实,归根结底这俩货都是属于 Number 类型:
isNaN & Number.isNaN
接着来聊 isNaN 和 Number.isNaN 俩方法。
我们都知道,虽然 NaN 作为 Number 类型,但是她不等于她自己,
NaN == NaN
或者NaN === NaN
都会返回 false,那么怎么检测一个 NaN 值呢?答案大家都知道了,isNaN 方法。好多东西传入 isNaN 的结果都是 true,并不只是 NaN,为什么?因为参数会先被强制转换成 Number 类型,然后再进行判断。
ok,强制转换后其实都变成了 NaN。
那么 Number.isNaN 和 isNaN 有何区别呢?和全局函数 isNaN() 相比,该方法不会强制将参数转换成数字,只有在参数是真正的数字类型,且值为 NaN 的时候才会返回 true。
值得注意的是,Number.isNaN 是 ES6 引入的,可以用上面的 Polyfill。
_.isNaN
最后来看看 underscore 对于 _.isNaN 的实现。
写代码首先得看需求,我们先看看 _.isNaN 的作用,查阅 API 文档 http://underscorejs.org/#isNaN:
文档指出,_.isNaN 和 native 的 isNaN 并不一样,必须是个 Number 类型(才可能返回 true),等等,似乎和 Number.isNaN 一样?且慢下结论。
我们来看看 edge 版本对其的实现(https://github.com/jashkenas/underscore/blob/master/underscore.js):
obj 得是个 Number 类型,并且能通过 isNaN 函数的判断,才能返回 true。其实能通过这个函数的,只有两个值,NaN 和 new Number(NaN)(当然还有 Number.NaN,前面说了,NaN 和 Number.NaN 是一样的东西,下同)。
而能通过 Number.isNaN 函数的只有 NaN。(
Number.isNaN(new Number(NaN)
会返回 false)但是我看的 1.8.3 其实是这样实现的:
其实这是有 BUG 的,很显然 new Number(0) 并不应该是 Not-A-Number。
为什么会这样写?这引发了我的好奇,找了下历史记录,是为了修复这个 issue https://github.com/jashkenas/underscore/issues/749。该 issue 认为,
_.isNaN(new Number(NaN))
应该返回 true。我们可以看下再之前的版本对于 _.isNaN 的实现(jashkenas/underscore@6ebb43f9b3ba88cc0cca712383534619b82f7e9b):
我又翻了下当时的测试数据(https://github.com/jashkenas/underscore/blob/6ebb43f9b3ba88cc0cca712383534619b82f7e9b/test/objects.js),发现当时没有类似 new Number(0) 的测试数据(现在已经有了)。
总结
对于 NaN 的判断,如果只针对 Number 类型,用 underscore 最新版的 _.isNaN 判断完全没有问题,或者用 ES6 的 Number.isNaN,两者的区别就在于一个 new Number(NaN),不过话又说回来,没人会这么蛋疼去这样 new 一个 NaN 吧?
The text was updated successfully, but these errors were encountered: