Respuestas:
El parámetro de contexto solo establece el valor de this
en la función de iterador.
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);
Ejemplo de trabajo: http://jsfiddle.net/a6Rx4/
Utiliza el número de cada miembro de la matriz que se itera para obtener el elemento en ese índice de someOtherArray
, que se representa this
desde que lo pasamos como parámetro de contexto.
Si no establece el contexto, this
se referirá al window
objeto.
context
es donde se this
refiere en su función de iterador. Por ejemplo:
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);
El contexto le permite proporcionar argumentos en el momento de la llamada, lo que permite una fácil personalización de las funciones auxiliares genéricas preconstruidas.
algunos ejemplos:
// 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);
Incluso a partir de los ejemplos limitados, puede ver cuán poderoso puede ser un "argumento adicional" para crear código reutilizable. En lugar de hacer una función de devolución de llamada diferente para cada situación, generalmente puede adaptar un asistente de bajo nivel. El objetivo es tener su lógica personalizada agrupando un verbo y dos sustantivos, con un mínimo repetitivo.
Es cierto que las funciones de flecha han eliminado muchas de las ventajas de "golf de código" de las funciones genéricas puras, pero las ventajas de semántica y consistencia permanecen.
Siempre agrego "use strict"
a los ayudantes para proporcionar [].map()
compatibilidad nativa al pasar primitivas. De lo contrario, se convierten en objetos, que por lo general todavía funcionan, pero es más rápido y seguro ser específico para cada tipo.
_.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>
Aquí hay un ejemplo simple que podría usar _.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();
Salida:
items: [ 'banana', 'apple', 'kiwi' ]
En lugar de llamar addItem
varias veces , puede usar subrayado de esta manera:
_.each(['banana', 'apple', 'kiwi'], function(item) { x.addItem(item); });
que es idéntico a llamar addItem
tres veces secuencialmente con estos elementos. Básicamente, itera su matriz y para cada elemento llama a su función de devolución de llamada anónima que llama x.addItem(item)
. La función de devolución de llamada anónima es similar a la addItem
función miembro (por ejemplo, toma un elemento) y no tiene sentido. Entonces, en lugar de pasar por una función anónima, es mejor que _.each
evite esta indirección y llame addItem
directamente:
_.each(['banana', 'apple', 'kiwi'], x.addItem);
pero esto no funcionará, ya que la addItem
función miembro dentro de la cesta this
no se referirá a la x
cesta que creó. Es por eso que tiene la opción de pasar su canasta x
para usarla como [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>
En resumen, si la función de devolución de llamada a la que pasa de _.each
alguna manera usa, this
entonces debe especificar a qué this
debería referirse dentro de su función de devolución de llamada. Puede parecer que x
es redundante en mi ejemplo, pero x.addItem
es sólo una función y podría ser totalmente ajenos a x
o basket
o cualquier otro objeto, por ejemplo :
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>
En otras palabras, enlaza algún valor this
dentro de su devolución de llamada, o bien puede usar el enlace directamente de esta manera:
_.each(['banana', 'apple', 'kiwi'], addItem.bind(x));
¿Cómo puede ser útil esta característica con algunos métodos diferentes de subrayado?
En general, si algún underscorejs
método toma una función de devolución de llamada y si desea que esa devolución de llamada se invoque en alguna función miembro de algún objeto (por ejemplo, una función que usa this
), puede vincular esa función a algún objeto o pasar ese objeto como [context]
parámetro y eso es La intención principal. Y en la parte superior de la documentación de subrayado, eso es exactamente lo que dicen: el iterado está vinculado al objeto de contexto, si se pasa uno
Como se explica en otras respuestas, context
es el this
contexto que se utilizará dentro de la devolución de llamada que se pasa each
.
Explicaré esto con la ayuda del código fuente de métodos relevantes del código fuente subrayado
La definición de _.each
o _.forEach
es la siguiente:
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; 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;
};
Es importante tener en cuenta la segunda declaración aquí
iteratee = optimizeCb(iteratee, context);
Aquí, context
se pasa a otro método optimizeCb
y la función devuelta desde allí se asigna a la iteratee
que se llama más tarde.
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) {
case 1:
return function(value) {
return func.call(context, value);
};
case 2:
return function(value, other) {
return func.call(context, value, other);
};
case 3:
return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4:
return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
Como se puede ver en la definición de método anterior optimizeCb
, si context
no se pasa, func
se devuelve como está. Si context
se pasa, la función de devolución de llamada se llama como
func.call(context, other_parameters);
^^^^^^^
func
Se llama con el call()
que se utiliza para invocar un método estableciendo el this
contexto del mismo. Entonces, cuando this
se usa adentro func
, se referirá a context
.
// Without `context`
_.each([1], function() {
console.log(this instanceof Window);
});
// With `context` as `arr`
var arr = [1, 2, 3];
_.each([1], function() {
console.log(this);
}, arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Puede considerarlo context
como el último parámetro opcional forEach
en JavaScript.
someOtherArray[num]
más quethis[num]
?