Antworten:
Der Kontextparameter legt nur den Wert von this
in der Iteratorfunktion fest.
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);
Arbeitsbeispiel: http://jsfiddle.net/a6Rx4/
Es verwendet die Nummer von jedem Mitglied des Arrays, das iteriert wird, um das Element an dem Index von zu erhalten someOtherArray
, der durch dargestellt wird, this
seit wir es als Kontextparameter übergeben haben.
Wenn Sie den Kontext nicht festlegen, this
wird auf das window
Objekt verwiesen.
context
Hier wird this
in Ihrer Iteratorfunktion darauf verwiesen. Beispielsweise:
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);
In diesem Kontext können Sie beim Aufruf Argumente bereitstellen und so die generischen vorgefertigten Hilfsfunktionen einfach anpassen.
einige Beispiele:
// 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);
Selbst anhand der begrenzten Beispiele können Sie sehen, wie leistungsfähig ein "zusätzliches Argument" für die Erstellung von wiederverwendbarem Code sein kann. Anstatt für jede Situation eine andere Rückruffunktion zu erstellen, können Sie normalerweise einen Helfer auf niedriger Ebene anpassen. Das Ziel ist, dass Ihre benutzerdefinierte Logik ein Verb und zwei Substantive mit minimalem Boilerplate bündelt.
Zwar haben Pfeilfunktionen viele der "Code Golf" -Vorteile generischer reiner Funktionen beseitigt, aber die semantischen und Konsistenzvorteile bleiben bestehen.
Ich füge immer "use strict"
Helfer hinzu, um native [].map()
Kompatibilität beim Übergeben von Grundelementen zu gewährleisten . Andernfalls werden sie zu Objekten gezwungen, was normalerweise immer noch funktioniert, aber es ist schneller und sicherer, typspezifisch zu sein.
_.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>
Hier ist ein einfaches Beispiel , das Folgendes verwenden könnte _.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();
Ausgabe:
items: [ 'banana', 'apple', 'kiwi' ]
Anstatt anzurufen addItem
mehrmals anzurufen, können Sie den Unterstrich folgendermaßen verwenden :
_.each(['banana', 'apple', 'kiwi'], function(item) { x.addItem(item); });
addItem
Dies ist identisch mit einem dreimaligen sequentiellen Aufruf mit diesen Elementen. Grundsätzlich iteriert es Ihr Array und ruft für jedes Element Ihre anonyme Rückruffunktion auf, die aufruft x.addItem(item)
. Die anonyme Rückruffunktion ähneltaddItem
Mitgliedsfunktion (z. B. nimmt sie ein Element) und ist irgendwie sinnlos. Anstatt eine anonyme Funktion zu durchlaufen, ist es besser, _.each
diese Indirektion zu vermeiden und addItem
direkt aufzurufen :
_.each(['banana', 'apple', 'kiwi'], x.addItem);
Dies addItem
funktioniert this
jedoch nicht , da sich die Mitgliederfunktion des Warenkorbs nicht auf Ihren von x
Ihnen erstellten Warenkorb bezieht . Deshalb haben Sie die Möglichkeit, Ihren Warenkorb weiterzugebenx
wie[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>
Kurz gesagt, wenn die Rückruffunktion, an die Sie _.each
in irgendeiner Weise übergeben werden, verwendet this
wird, müssen Sie angeben, worauf this
in Ihrer Rückruffunktion Bezug genommen werden soll. Es mag wie x
überflüssig in meinem Beispiel ist, sondern x.addItem
ist nur eine Funktion und könnte völlig unabhängig von x
oder basket
oder einem anderen Objekt, zum Beispiel :
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>
Mit anderen Worten, Sie binden einen Wert an this
Ihren Rückruf, oder Sie können bind auch direkt wie folgt verwenden:
_.each(['banana', 'apple', 'kiwi'], addItem.bind(x));
Wie kann diese Funktion bei verschiedenen Unterstrichmethoden nützlich sein?
Wenn eine underscorejs
Methode eine Rückruffunktion verwendet und dieser Rückruf für eine Elementfunktion eines Objekts (z. B. eine verwendete Funktion this
) aufgerufen werden soll, können Sie diese Funktion im Allgemeinen an ein Objekt binden oder dieses Objekt als [context]
Parameter übergeben, und das ist die primäre Absicht. Und ganz oben in der Dokumentation zu Unterstrichen steht genau das: Der Iterat ist an das Kontextobjekt gebunden, wenn eines übergeben wird
Wie in anderen Antworten erläutert, context
wird der this
Kontext, der innerhalb des Rückrufs verwendet werden soll, an übergeben each
.
Ich werde dies mit Hilfe des Quellcodes der relevanten Methoden aus erklären Unterstrich
Die Definition von _.each
oder _.forEach
lautet wie folgt:
_.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;
};
Die zweite Aussage ist hier wichtig zu beachten
iteratee = optimizeCb(iteratee, context);
Hier context
wird an eine andere Methode übergeben optimizeCb
und die von ihr zurückgegebene Funktion wird dann zugewiesen, iteratee
die später aufgerufen wird.
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);
};
};
Wie aus der obigen Methodendefinition von ersichtlich ist optimizeCb
, context
wird , wenn nicht bestanden, func
zurückgegeben, wie es ist. Wenn context
übergeben, wird die Rückruffunktion als aufgerufen
func.call(context, other_parameters);
^^^^^^^
func
wird aufgerufen, mit call()
dem eine Methode aufgerufen wird, indem der this
Kontext festgelegt wird. Wenn this
es also im Inneren verwendet wird func
, bezieht es sich auf 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>
Sie können context
als letzten optionalen Parameter forEach
in JavaScript betrachten.
someOtherArray[num]
eher auf als beziehenthis[num]
?