The _.each function accepts an array or an object, an iteratee function and an optional context object, the iteratee function is invoked once and in order for each array item The iteratee function provides 3 arguments item - The current iterated object (or value if an object was passed) i - The index of the iterated ...
Lodash is extremely well-optimized as far as modern JS goes, but, as you may know, nothing can be faster than native implementation. Even if Lodash uses the same API under-the-hood, function call overhead is still present.
The context parameter just sets the value of this
in the iterator function.
var someOtherArray = ["name","patrick","d","w"];
_.each([1, 2, 3], function(num) {
// In here, "this" refers to the same Array as "someOtherArray"
alert( this[num] ); // num is the value from the array being iterated
// so this[num] gets the item at the "num" index of
// someOtherArray.
}, someOtherArray);
Working Example: http://jsfiddle.net/a6Rx4/
It uses the number from each member of the Array being iterated to get the item at that index of someOtherArray
, which is represented by this
since we passed it as the context parameter.
If you do not set the context, then this
will refer to the window
object.
context
is where this
refers to in your iterator function. For example:
var person = {};
person.friends = {
name1: true,
name2: false,
name3: true,
name4: true
};
_.each(['name4', 'name2'], function(name){
// this refers to the friends property of the person object
alert(this[name]);
}, person.friends);
The context lets you provide arguments at call-time, allowing easy customization of generic pre-built helper functions.
some examples:
// stock footage:
function addTo(x){ "use strict"; return x + this; }
function pluck(x){ "use strict"; return x[this]; }
function lt(x){ "use strict"; return x < this; }
// production:
var r = [1,2,3,4,5,6,7,8,9];
var words = "a man a plan a canal panama".split(" ");
// filtering numbers:
_.filter(r, lt, 5); // elements less than 5
_.filter(r, lt, 3); // elements less than 3
// add 100 to the elements:
_.map(r, addTo, 100);
// encode eggy peggy:
_.map(words, addTo, "egg").join(" ");
// get length of words:
_.map(words, pluck, "length");
// find words starting with "e" or sooner:
_.filter(words, lt, "e");
// find all words with 3 or more chars:
_.filter(words, pluck, 2);
Even from the limited examples, you can see how powerful an "extra argument" can be for creating re-usable code. Instead of making a different callback function for each situation, you can usually adapt a low-level helper. The goal is to have your custom logic bundling a verb and two nouns, with minimal boilerplate.
Admittedly, arrow functions have eliminated a lot of the "code golf" advantages of generic pure functions, but the semantic and consistency advantages remain.
I always add "use strict"
to helpers to provide native [].map()
compatibility when passing primitives. Otherwise, they are coerced into objects, which usually still works, but it's faster and safer to be type-specific.
_.each(['Hello', 'World!'], function(word){
console.log(word);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Here's simple example that could use _.each
:
function basket() {
this.items = [];
this.addItem = function(item) {
this.items.push(item);
};
this.show = function() {
console.log('items: ', this.items);
}
}
var x = new basket();
x.addItem('banana');
x.addItem('apple');
x.addItem('kiwi');
x.show();
Output:
items: [ 'banana', 'apple', 'kiwi' ]
Instead of calling addItem
multiple times you could use underscore this way:
_.each(['banana', 'apple', 'kiwi'], function(item) { x.addItem(item); });
which is identical to calling addItem
three times sequentially with these items. Basically it iterates your array and for each item calls your anonymous callback function that calls x.addItem(item)
. The anonymous callback function is similar to addItem
member function (e.g. it takes an item) and is kind of pointless. So, instead of going through anonymous function it's better that _.each
avoids this indirection and calls addItem
directly:
_.each(['banana', 'apple', 'kiwi'], x.addItem);
but this won't work, as inside basket's addItem
member function this
won't refer to your x
basket that you created. That's why you have an option to pass your basket x
to be used as [context]
:
_.each(['banana', 'apple', 'kiwi'], x.addItem, x);
function basket() {
this.items = [];
this.addItem = function(item) {
this.items.push(item);
};
this.show = function() {
console.log('items: ', this.items);
}
}
var x = new basket();
_.each(['banana', 'apple', 'kiwi'], x.addItem, x);
x.show();
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
In short, if callback function that you pass to _.each
in any way uses this
then you need to specify what this
should be referring to inside your callback function. It may seem like x
is redundant in my example, but x.addItem
is just a function and could be totally unrelated to x
or basket
or any other object, for example:
function basket() {
this.items = [];
this.show = function() {
console.log('items: ', this.items);
}
}
function addItem(item) {
this.items.push(item);
};
var x = new basket();
_.each(['banana', 'apple', 'kiwi'], addItem, x);
x.show();
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
In other words, you bind some value to this
inside your callback, or you may as well use bind directly like this:
_.each(['banana', 'apple', 'kiwi'], addItem.bind(x));
how this feature can be useful with some different underscore methods?
In general, if some underscorejs
method takes a callback function and if you want that callback be called on some member function of some object (e.g. a function that uses this
) then you may bind that function to some object or pass that object as the [context]
parameter and that's the primary intention. And at the top of underscorejs documentation, that's exactly what they state: The iteratee is bound to the context object, if one is passed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With