javascript - How to re-write _.every/_.all from Underscore.js using _.reduce (and _.each) -
javascript - How to re-write _.every/_.all from Underscore.js using _.reduce (and _.each) -
i'm working on re-writing underlying code many of standard underscore.js functions work on javascript skills , bit stuck _.every
/_.all
. appears in library itself, _.every
/_.all
function written using existing _.each
function, beingness encouraged write version using version of _.reduce
(which incorporates version of _.each
). i've provided code both functions below.
the first test _.every
function (see below well) fails 1 false values passed in using _.identity
function (simply homecoming value entered argument) iterator:
test:
it('fails collection of all-falsy results', function() { expect(_.every([null, 0, undefined], _.identity)).to.equal(false); });
i have few questions why _.every
function failing test shown above, along multiple other tests (e.g.; mixed true/false values, undefined values, etc.):
-when calling iterator function, need utilize iterator.call
or iterator.apply
? if so, utilize , how specify arguments?
-what benefit there using _.reduce
here rather _.each
, when underscore.js library not utilize _.reduce
?
-why homecoming need called twice, 1 time when calling _.reduce
function, , 1 time within anonymous function defined within _.reduce
(i've wondered when building functions utilize _.map
function)? me, seems returning result of _.reduce
function, returning something.
_.every:
_.every = function(collection, iterator) { // tip: seek re-using reduce() here. homecoming _.reduce(collection, function(allfound, item) { homecoming iterator(item) && allfound; }, true); };
_.each:
_.each = function(collection, iterator) { // define spec arrays if (array.isarray(collection)) { for(var = 0; < collection.length; i++) { iterator(collection[i], i, collection); } } // define spec objects else { for(var key in collection) { iterator(collection[key], key, collection); } } };
_.reduce:
_.reduce = function(collection, iterator, accumulator) { // add together status set accumulator if no explicit starting value given. if (arguments.length < 3) { accumulator = collection[0]; } _.each(collection, function(value) { accumulator = iterator(accumulator, value); }); homecoming accumulator; };
your test isn't passing because it's not returning false
expected (though returning falsey value).
_.every = function(collection, iterator) { homecoming _.reduce(collection, function(allfound, item) { homecoming iterator(item) && allfound; }, true); };
what happens when homecoming iterator(item) && allfound
if iterator(item)
falsey (but not false
), not homecoming false
, value of iterator(item)
. verify yourself, open repl, , type undefined && true
; result undefined
, not false
.
so if want explicitly homecoming false
, , not falsey value, you'll have coerce boolean. can either boolean(truthy_or_falsey_value)
or !!truthy_or_falsey_value
. prefer latter, alter implementation thusly:
_.every = function(collection, iterator) { homecoming _.reduce(collection, function(allfound, item) { homecoming !!iterator(item) && allfound; }, true); };
your other questions:
when calling iterator function, need utilize iterator.call or iterator.apply? if so, utilize , how specify arguments?
it depends on goal is. call
, apply
used when want command value of this
keyword in function body. of javascript's built-in array methods (like array.prototype.map
, array.prototype.filter
) take thisarg
, supplied callback using call
or apply
. far difference between call
, apply
, it's how arguments handled. see this answer more details.
what benefit there using reduce
here rather each
, when underscore.js library not utilize reduce
?
probably none, or little. there performance difference, best way find out profile both approaches.
why homecoming need called twice, 1 time when calling _.reduce function, , 1 time within anonymous function defined within _.reduce
if want function -- function -- homecoming value, must phone call homecoming within function. can't expect phone call return
inner function, , expect enclosing function magically understand it's supposed to, in turn, homecoming value of called function. languages default returning value of lastly look in function if return
isn't explicitly called, either convenient or confusing, depending on perspective. if have experience such language (ruby, example), return
statements may seem little excessive you.
as editorial note, sense iterator
poor naming selection testing function. not iterating on (the function it's argument doing iteration). improve name might generic callback
or cb
. term "predicate" means function maps value true
or false
, preferred terminology. mutual selection test
, since is, after all, function that's performing binary filter on argument.
javascript underscore.js
Comments
Post a Comment