3

我一直在阅读underscore.js源代码并注意到这个比较_.each():

(obj.length === +obj.length)

我知道 + 在变量将其转换为数字/整数之前。所以在这个原因

[1,2,3].length === +[1,2,3].length

是真的。如果我传入一个对象:

var obj = {a: 1, b: 2, c: 3};

+obj.length产生NaN

在最后一种情况下,我有

[1,2,3, {a: [4,5,6]}].length

这是 4. 将其转换为一个数字.. 仍然是 4。

else case决定,我可以看到这种比较可能是为了区分数组和对象,就像它使用的 else case 一样:

  for (var key in obj) { ...

我看不出有任何理由使用这种比较。谁能解释一下?

4

4 回答 4

6

基本上,这是一种测试length属性类型的方法,Number不使用typeof 并且数字不是NaN。所以实际上:

if (typeof obj.length === "number" && !isNaN(obj.length))

比较n === +n仅适用于数字,因为===测试类型和值,+n并将创建一个Number(可能,如您所见,数字NaN)。因为NaN === NaN是假的,所以它也会把它们淘汰掉。

因此,根据一个定义(“有一个length不是的数字NaN”),这是一种检测要迭代的对象是否是数组的方法。在 JavaScript 和浏览器世界中有几个类似数组的东西,例如arguments伪数组和 DOM 的NodeLists。


愚蠢的性能比较:

结果:没有NaN方面,typeof速度更快(当类型错误时明显如此)。对于NaN方面,+当结果为时更快,当结果true为 false 时,因为它是NaN,而当结果为错误时,速度较慢(明显如此),false因为它是错误的类型。(当然,Opera 一如既往地不同。)

并不是说它在现实世界中可能很重要(参见上面的“愚蠢”)。

于 2013-07-01T07:34:22.203 回答
1

Object我想这是一种将实例与Array实例或“ Arrayish ”对象(如)区分开来的快速方法arguments

Object如果实例包含length属性,它将中断。喜欢{a:1, length: 1},或作为结果[].push.call({},'a value')(结果将是:){0:'a value',length: 1}。如this jsFiddle所示

于 2013-07-01T07:34:33.400 回答
1

从上下文来看,我认为它试图弄清楚是否obj是一个数组,因为迭代一个需要顺序for循环而不是for- inhttps ://stackoverflow.com/a/3010848/367273

于 2013-07-01T07:34:44.893 回答
0

+ 运算符返回对象的数字表示形式。因为您的代码 +obj.length 意味着它返回一个数字引用 .... this。当它是一个数组时,您将 +obj.length 值作为 Number 但它不返回长度以防 var obj = {a: 1, b: 2, c: 3}; 因为它不是一个数组......当你使用 [1,2,3, {a: [4,5,6]}].length 它返回 4 作为对象在数组中......

于 2013-07-01T07:46:17.553 回答