我正在对一些流行的js进行代码审查,并且我从underscore.js开始。

现在,我正在分析_.max函数:

  _.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity,
    value, computed;
if (iteratee == null && obj != null) {
  obj = obj.length === +obj.length ? obj : _.values(obj);
  for (var i = 0, length = obj.length; i < length; i++) {
    value = obj[i];
    if (value > result) {
      result = value;
    }
  }
} else {
  iteratee = _.iteratee(iteratee, context);
  _.each(obj, function(value, index, list) {
    computed = iteratee(value, index, list);
    if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
      result = value;
      lastComputed = computed;
    }
  });
}
return result;
};


而且我不明白为什么要使用它

computed > lastComputed || computed === -Infinity && result === -Infinity

代替

computed > lastComputed

在if条件下提供iteratee。

我认为,如果仅使用“ compute> lastComputed”,则性能更高(很少)
在任何情况下-Infinity出现在集合(一个,一些或所有元素)中。

如果我错了,我想知道。

谢谢,
巴勃罗·贝尼托(Pablo Benito)

最佳答案

它可能会或可能不会更好,但是肯定会有所不同。 Underscore的作者显然希望它执行其执行方式。

它会以不同方式执行的一种方法是针对一个元素集合((错误命名)iteratee返回-Infinity):



var yourMax = function(obj, iteratee, context) {
  var result = -Infinity, lastComputed = -Infinity,
      value, computed;
  if (iteratee == null && obj != null) {
    obj = obj.length === +obj.length ? obj : _.values(obj);
    for (var i = 0, length = obj.length; i < length; i++) {
      value = obj[i];
      if (value > result) {
        result = value;
      }
    }
  } else {
    iteratee = _.iteratee(iteratee, context);
    _.each(obj, function(value, index, list) {
      computed = iteratee(value, index, list);
      if (computed > lastComputed) {
        result = value;
        lastComputed = computed;
      }
    });
  }
  return result;
};

var result;
var entries = [{name: 'foo', value: 42}];
result = _.max(entries, function(entry){
  return entry.name === 'foo' ? -Infinity : entry.value;
});
snippet.log("_.max Result: " + result.name);

result = yourMax(entries, function(entry){
  return entry.name === 'foo' ? -Infinity : entry.value;
});
snippet.log("yourMax Result: " + result.name);

<!-- Temporary snippet object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<script src="http://jashkenas.github.io/underscore/underscore-min.js"></script>





如果要对其进行微优化,则不会改变其工作方式的更改将是在computed回调中而不是在包含范围内声明_.each,因为它仅在该回调中使用。从理论上讲,解析computed时,引擎必须先查看绑定对象以获取对回调的调用的上下文,然后在此处找不到它,而是查看外部绑定对象以找到它。因此,通过将其移至更接近实际使用的位置,我们可以让引擎立即找到它,而不会有最初的遗漏:

_.bettermax = function(obj, iteratee, context) {
    var result = -Infinity,
        lastComputed = -Infinity,
        value; // <=== `computed` not declared here
    if (iteratee == null && obj != null) {
        obj = obj.length === +obj.length ? obj : _.values(obj);
        for (var i = 0, length = obj.length; i < length; i++) {
            value = obj[i];
            if (value > result) {
                result = value;
            }
        }
    } else {
        iteratee = _.iteratee(iteratee, context);
        _.each(obj, function(value, index, list) {
            // vv `computed` declared here
            var computed = iteratee(value, index, list);
            if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
                result = value;
                lastComputed = computed;
            }
        });
    }
    return result;
};


增益很小,但可以察觉:http://jsperf.com/move-variable-closer-to-use

08-18 17:05