最近看一下underscore, 顺便也看了下源码, 不过第一个函数就碰到了奇葩:
1 | obj.length === +obj.length |
看了半天愣是没懂…
###0x00 分析.
结论先: 这条语句可以用来判断obj是数组还是对象.
别急啦~我先来抄一段underscore的each函数实现.
1 | var each = _.each = _.forEach = function(obj, iterator, context) { |
我也是第一次看到这种写法, 甚至刚开始让我怀疑我的js语法学的是不是有问题了.
我们先看两个地方:
=== 全等符
+ 号
-> 我们知道全等符是用来判断其左右两个变量在值与类型上是不是”完全相等的”. 出于性能以及各种奇葩的问题, 在捣鼓拉斯的js语言精粹里他就强烈推荐尽量使用===来代替==.
-> 再来看看+号, 这个操作符能自动转换它右边的操作值为number类型. 不知道同学们在做js的数学运算的有没有碰到过这个数: NaN, 它的意思是Not A Number. 一般在对undefined进行数学操作的时候会返回NaN这个值, 比如 a = undefined + 1; //-> a == NaN. 其实就是这个意思, 如果obj是array/ string/ function, 那么它就拥有length这个number类型的属性, 左边和右边是全等的. 如果obj是对象, 那么obj.length就是undefined, 那么+undefined就是NaN ,undefined === NaN自然就是false了.
(关于NaN, Js还有一个奇葩的遗留问题, NaN === NaN的结果是False, 这也是判断一个数是不是NaN的方法)
###0x01 为什么这样写
我们来实现一下好理解一些的版本:1
typeof obj.length === "number" && !isNaN(obj.length)
其实用typeof来判断array和对象也是可行的, 我们用jsperf来测试一下这两个语句的性能;
这里存在两种情况, 判断obj是Array或者obj是对象:
我的测试环境是 Safari 7.0.2 @ OS X 10.9.2, Chrome @ OSX 也大同小异.
OK, 结论是在判断obj是对象的时候, 使用typeof性能占优势.
###0x03 结论
我们大概可以猜测到作者在写underscore的时候考虑到each方法大部分时候面对的是array, 所以选择了一种对array来说性能占优的方式.
参考: