4

下划线的最新代码中,第 211 行,内容为

result || (result = iterator.call(context, value, index, list))) return breaker;

是否需要 or 语句?可以换成

(result = iterator.call(context, value, index, list))) return breaker; // ?

result最初设置为 false,除了这一行之外,代码中没有其他地方被修改。

请注意,如果 JavaScript 或 (||) 语句为真,则返回第一个操作数,如果它('it' 是第一个操作数)为假,则返回第二个操作数。这直接来自 Crockford, The Good Parts。还注意到 || 做一个或与真/假值不是真/假值。

这是从上面的链接复制的整个方法:

var any = _.some = _.any = function(obj, iterator, context) {
    iterator || (iterator = _.identity);
    var result = false;
    if (obj == null) return result;
    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
    each(obj, function(value, index, list) {
      if (result || (result = iterator.call(context, value, index, list))) return breaker;
    });
    return !!result;
  };
4

2 回答 2

7

这让我认为result||检查是为了以防万一......或支持forEach定义的环境(例如通过垫片),但some不是。

正如评论中所指出的,underscore 对本机循环方法(和朋友)的依赖forEach似乎map不是一个好主意,原因如下:

  • 它们比简单的循环
  • 你不能打破(好吧,你可以有一个专门的例外,但下划线不会这样做)
  • Array.prototype可以被其他(恶意或愚蠢的)代码篡改
于 2013-06-28T14:25:41.000 回答
3

答案是:是的,如果是原生代码,可以按照建议的方式进行优化。

为了理解会发生什么,让我们先将代码简化为这里重要的部分:

var result = false;
for (var i in obj)
{
    if (result || (result = call(i)))
        return;
}

这意味着,如果要么result已经是非假的,它就会返回,或者如果call()返回一个非假的值,它就会返回。由于结果仅由 更改call(),因此第一次检查result是多余的。

var result = false;
for (var i in obj)
{
    if (result = call(i))
        return;
}

一旦call()提供了非假值,此代码仍将返回。

也因为each()是一个库函数,并且 OPbreaker在找到的项目上返回

真正发生的是:

var result = false;
for (var i in obj)
{
    if (result || (result = call(i)))
        break;
}

在这种情况下,只要使用库 foreach 函数,仍然可以按照建议的方式优化代码。循环将保留在找到的值上。

令人困惑的部分是它each()是一个库函数,并使用一个函数来模拟循环体。从主体函数返回库常量breaker将退出循环。

一旦each()决定使用原生.forEach() 代码就不能再优化了,因为.forEach()不会理解breaker!有关详细信息,请参阅thg435的答案!

于 2013-06-28T14:21:51.943 回答