3

这是下划线中的一行代码。这一行的加号前缀是什么?

if (obj.length === +obj.length) { // plus prefix?
4

5 回答 5

4

添加+符号可以有效地将变量转换为数字,例如:

+"1" === 1;

但是,请注意

+"1" === "1"; // FALSE
+"1" ==  "1"; // TRUE

这是因为==会将其操作数转换为相同的类型,而===不会。

这意味着测试:

obj.length === +obj.length

本质上是试图测试是否obj.length是数字。

在 Underscore 中,此代码试图确定未知类型的变量是否具有已调用的属性length以及它是否为数字。假设是,如果这两个都是真的,你可以迭代变量是如果它是一个数组。

编辑

请注意,OP 的代码中有许多错误,其中最重要的是这种检测某事物是否为数组(或类似数组)的方法。以下对象会导致问题:

var footballField = {
    covering: "astroturf",
    condition: "muddy",
    length: 100
};

我不提倡上述方法......只是解释别人的。

于 2013-02-26T00:15:29.933 回答
3

加号前缀将变量转换为数字。基本上,这obj.length === +obj.length是 obj.length 真的是一个数字的健全性检查。如果obj.length不是数字,例如 string "foo",则"foo" === +"foo"等于 false ,因为+"foo"输出为NaN

于 2013-02-26T00:18:11.140 回答
1

+ 前缀将值转换为数字。

于 2013-02-26T00:15:14.823 回答
1

这迫使 的值为obj.lengtha Number。本质上,这样做是为了确保length类数组对象的默认值没有被覆盖,以便可以正确迭代。

breaker在这种情况下不会做任何事情,因为即使没有等价比较,即使是另一个空对象也会在与 .. 进行比较时进行{}评估。falsebreaker

但是,breaker没有在该上下文中使用,因为它是在函数之外.each定义的,这看起来与您在此处显示的不同。相反,它用于从其他循环方法中强制“中断”:

_.every = _.all = function(obj, iterator, context) {
  /* snip */
  if (!(result = result && iterator.call(context, value, index, list)))
      return breaker;

你可以看到,如果结果在“every”中不是真的,我们想立即打破。 _.every调用_.each,它会返回breaker与自身比较时为真,允许立即中断。

于 2013-02-26T00:18:35.717 回答
-1

如果对象没有length属性(是一个常规的Object,而不是一个Array),那么调用obj.length将返回undefined。对 undefined 的测试会更清楚,但实现者选择首先将其转换为数字(因此它将变为NaN),然后将其与原始值进行比较(使用严格比较,这将确保它会产生false)。

更新:正如其他人指出的那样,这段代码似乎不仅关注Arrays,还关注“类数组”对象(即具有数字length属性和数字索引的对象)。在这种情况下,instanceof Array仅测试 for 是不够的(仅测试 forundefined可能不是最佳选择,因为可能存在length另一种类型的 but)。

于 2013-02-26T00:15:04.823 回答