Friday 15 May 2015

javascript - max function implementation on underscore -



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