javascript - max function implementation on underscore -
i in code-reviewing popular js, , begun underscore.js.
now analyzing _.max function :
_.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); (var = 0, length = obj.length; < 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; } }); } homecoming result; };
and don't understand why used
computed > lastcomputed || computed === -infinity && result === -infinity
instead of
computed > lastcomputed
in if status when iteratee provided.
i think more performant ( little ) if utilize "computed > lastcomputed" in case -infinity appear in collection ( one, some, or elements ).
if wrong, wants know what.
thanks, pablo benito
it might or might not perform better, perform differently. apparently underscore authors wanted perform way performs.
one way in perform differently one-element collection (misnamed) iteratee
returns -infinity
:
class="snippet-code-js lang-js prettyprint-override">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); (var = 0, length = obj.length; < 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; } }); } homecoming result; }; var result; var entries = [{name: 'foo', value: 42}]; result = _.max(entries, function(entry){ homecoming entry.name === 'foo' ? -infinity : entry.value; }); snippet.log("_.max result: " + result.name); result = yourmax(entries, function(entry){ homecoming entry.name === 'foo' ? -infinity : entry.value; }); snippet.log("yourmax result: " + result.name);
class="snippet-code-html lang-html prettyprint-override"><!-- 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>
if want micro-optimize it, alter doesn't alter how works declare computed
within _.each
callback rather in containing scope, since it's ever used within callback. in theory, when resolving computed
, engine has @ binding object context of phone call callback first , then, not finding there, @ outer binding object find it. moving closer it's used, allow engine find rather having initial miss:
_.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); (var = 0, length = obj.length; < 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; } }); } homecoming result; };
the gain tiny, perceptible: http://jsperf.com/move-variable-closer-to-use
javascript performance underscore.js
No comments:
Post a Comment