I'm using UnderscoreJs. Consider this code:
var docs = [
{name : 'Anders', niche : 'Web Development'},
{name : 'Johnny', niche : 'Design'},
{name : 'Eric', niche : 'PhotoShop'}
];
var newDocs = _.map(docs, function (doc){
delete doc.niche;
return doc;
});
I doesn't matter if I use .each
or .map
here. The outcome is exactly the same.
What is really the difference between the two in the case above?
map
is intended to be a functional mapping method: its function argument should return a value, but is not expected to have any side-effects.
each
is just a functional replacement for an imperative for
loop: its purpose is to have an effect, and it is not expected to return any value.
For example, this would be a more appropriate use for map
:
var docs = getDocs();
var docTitles = _.map(docs, function (doc){
return doc.title;
});
// expect `docs` to be unchanged
Whereas this would be an appropriate use for each
:
var docs = getDocs();
_.each(docs, function (doc){
delete doc.niche;
});
// expect `docs` to be altered.
Iterates over a list of elements, yielding each in turn to an iteratee function.
Each invocation of iteratee is called with three arguments: (element, index, list). If list is a JavaScript object, iteratee's arguments will be (value, key, list). Returns the list for chaining.
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...
Produces a new array of values by mapping each value in list through a transformation function (iteratee).
If list is a JavaScript object, iteratee's arguments will be (value, key, list).
_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]
see documentation
You can just look at the source code to see the difference:
_.each = _.forEach = function(obj, iteratee, context) {
if (obj == null) return obj;
iteratee = createCallback(iteratee, context);
var i, length = obj.length;
if (length === +length) {
for (i = 0; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
_.map = _.collect = function(obj, iteratee, context) {
if (obj == null) return [];
iteratee = _.iteratee(iteratee, context);
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length,
results = Array(length),
currentKey;
for (var index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
Your assertion that the results are "exactly the same" is untrue. The _.each()
function returns the original list, but _.map()
returns a new list. You're directly modifying the original objects as you go, so you end up with references to the same objects in each list, but with _.map()
you end up with two separate array instances.