Ich habe das schon erwägt, von underscorejs:Wie optimizeCb in Unterstrichen funktioniert?
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);
};
};
Also, anscheinend diese Optimierung gilt nur für Rückruf, der this
Wert setzt (hier context
genannt). Wie unterscheidet sich das von Call call
direkt zum Callback? Wie kann dies die Leistung verbessern?
Es ist in Ordnung, wenn die Optimierung nur für ältere JS-Engines gültig ist. Ich will es nur wissen.
Bearbeiten
Ich war wahrscheinlich unklar in der Frage. Das ist was ich meine. Nehmen wir ein Beispiel nehmen, wo optimizeCb verwendet wird:
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context); //REMOVE this
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
//REPLACE with iteratee.call(context, 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 2 Kommentare Siehe: iteratee = optimizeCb(iteratee, context); //REMOVE this
und iteratee(obj[i], i, obj); //REPLACE with iteratee.call(context, obj[i], i, obj);
. Ich verstehe Argumente ist langsam und anwenden ist langsam. Aber ich sehe nicht, wie Argumente und Anruf vs gelten hier ins Spiel kommen? Ich sehe keinen Unterschied zwischen zwei Ansätzen.
Ich denke, das Schlüsselproblem ist, dass, wenn ein Callback an eine bestimmte Unterstreichungsmethode übergeben wird, dann ist die Signatur bereits bekannt. Zum Beispiel muss der Rückruf, der an _.each
übergeben wurde, function(value, index, collection)
haben. Diese Beobachtung wird in der Art bestätigt, wie optimizeCb aufgerufen wird: Wenn der Aufrufer von optimizeCb den Parameter argCount bereitstellen kann (leer lassen bedeutet, dass er 3 ist), weiß er, welche Signatur er ist.
Kann jemand weiter ausarbeiten? Danke vielmals!
"Anruf" ist nur viel schneller https://jsperf.com/call-apply-segu. Ich denke, weil es auf Argumentenarray nicht zugreifen muss –
@Moogs: Der Test, mit dem Sie verbunden sind, vergleicht Äpfel nicht mit Äpfeln; Ich denke, das tut es: http://jsperf.com/call-apply-segu/53 Es gibt jedoch noch einen klaren Vorteil, wenn man 'apply' aufruft. –