Réponses:
Le paramètre context définit simplement la valeur de this
dans la fonction d'itérateur.
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);
Exemple de travail: http://jsfiddle.net/a6Rx4/
Il utilise le numéro de chaque membre du tableau en cours d'itération pour obtenir l'élément à cet index de someOtherArray
, qui est représenté par this
puisque nous l'avons passé en tant que paramètre de contexte.
Si vous ne définissez pas le contexte, alors this
fera référence à l' window
objet.
context
est où this
fait référence dans votre fonction d'itérateur. Par exemple:
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);
Le contexte vous permet de fournir des arguments au moment de l'appel, permettant une personnalisation facile des fonctions d'assistance génériques pré-construites.
quelques exemples:
// 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);
Même à partir des exemples limités, vous pouvez voir à quel point un "argument supplémentaire" peut être puissant pour créer du code réutilisable. Au lieu de créer une fonction de rappel différente pour chaque situation, vous pouvez généralement adapter un assistant de bas niveau. L'objectif est d'avoir votre logique personnalisée regroupant un verbe et deux noms, avec un minimum de passe-partout.
Certes, les fonctions fléchées ont éliminé de nombreux avantages de «code golf» des fonctions pures génériques, mais les avantages sémantiques et de cohérence demeurent.
J'ajoute toujours "use strict"
aux helpers pour fournir une [].map()
compatibilité native lors du passage des primitives. Sinon, ils sont forcés en objets, ce qui fonctionne généralement toujours, mais il est plus rapide et plus sûr d'être spécifique au type.
_.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>
Voici un exemple simple qui pourrait utiliser _.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();
Production:
items: [ 'banana', 'apple', 'kiwi' ]
Au lieu d'appeler addItem
plusieurs fois, vous pouvez utiliser le soulignement de cette façon:
_.each(['banana', 'apple', 'kiwi'], function(item) { x.addItem(item); });
ce qui revient à appeler addItem
trois fois de manière séquentielle avec ces éléments. Fondamentalement, il itère votre tableau et pour chaque élément appelle votre fonction de rappel anonyme qui appelle x.addItem(item)
. La fonction de rappel anonyme est similaire à la addItem
fonction membre (par exemple, elle prend un élément) et est un peu inutile. Donc, au lieu de passer par une fonction anonyme, il vaut mieux _.each
éviter cette indirection et appeler addItem
directement:
_.each(['banana', 'apple', 'kiwi'], x.addItem);
mais cela ne fonctionnera pas, car la addItem
fonction membre de l' intérieur du panier this
ne fera pas référence à votre x
panier que vous avez créé. C'est pourquoi vous avez la possibilité de passer votre panier x
pour être utilisé comme [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 bref, si la fonction de rappel à laquelle vous passez d' _.each
une manière ou d'une autre utilise, this
vous devez spécifier ce à quoi vous devez this
faire référence dans votre fonction de rappel. Cela peut sembler x
redondant dans mon exemple, mais ce x.addItem
n'est qu'une fonction et pourrait être totalement indépendante de x
ou basket
ou de tout autre objet, par exemple :
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 d'autres termes, vous liez une valeur à l' this
intérieur de votre rappel, ou vous pouvez également utiliser bind directement comme ceci:
_.each(['banana', 'apple', 'kiwi'], addItem.bind(x));
comment cette fonctionnalité peut être utile avec certaines méthodes de soulignement différentes?
En général, si une underscorejs
méthode prend une fonction de rappel et si vous voulez que ce rappel soit appelé sur une fonction membre d'un objet (par exemple, une fonction qui utilise this
), vous pouvez lier cette fonction à un objet ou passer cet objet comme [context]
paramètre et c'est l'intention première. Et en haut de la documentation de underscorejs, c'est exactement ce qu'ils déclarent: l'iteratee est lié à l'objet de contexte, s'il est passé
Comme expliqué dans d'autres réponses, context
le this
contexte à utiliser dans le rappel est-il passé each
.
Je vais vous expliquer cela à l'aide du code source des méthodes pertinentes à partir du code source de soulignement
La définition de _.each
ou _.forEach
est la suivante:
_.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;
};
La deuxième déclaration est importante à noter ici
iteratee = optimizeCb(iteratee, context);
Ici, context
est passé à une autre méthode optimizeCb
et la fonction renvoyée par celle-ci est ensuite affectée à iteratee
laquelle est appelée ultérieurement.
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);
};
};
Comme on peut le voir à partir de la définition de méthode ci-dessus optimizeCb
, si context
n'est pas passé, il func
est renvoyé tel quel. Si context
est passé, la fonction de rappel est appelée comme
func.call(context, other_parameters);
^^^^^^^
func
est appelé avec call()
lequel est utilisé pour invoquer une méthode en définissant son this
contexte. Donc, quand il this
est utilisé à l'intérieur func
, il fera référence à 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>
Vous pouvez considérer context
comme le dernier paramètre facultatif forEach
dans JavaScript.
someOtherArray[num]
plutôt quethis[num]
?