我正在对一些流行的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