Wie kann man Funktionsargumente binden, ohne dies zu binden?
Lesezeit: 7 Minuten
Durchdringen
Wie kann ich in Javascript Argumente an eine Funktion binden, ohne die this Parameter?
Zum Beispiel:
//Example function.
var c = function(a, b, c, callback) {};
//Bind values 1, 2, and 3 to a, b, and c, leave callback unbound.
var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope?
Wie kann ich den Nebeneffekt vermeiden, den Bereich der Funktion binden zu müssen (z. B. setting this = null) auch?
Bearbeiten:
Sorry für die Verwirrung. Ich möchte Argumente binden, dann in der Lage sein, die gebundene Funktion später aufzurufen und sie sich genau so verhalten zu lassen, als hätte ich die ursprüngliche Funktion aufgerufen und ihr die gebundenen Argumente übergeben:
var x = 'outside object';
var obj = {
x: 'inside object',
c: function(a, b, c, callback) {
console.log(this.x);
}
};
var b = obj.c.bind(null, 1, 2, 3);
//These should both have exact same output.
obj.c(1, 2, 3, function(){});
b(function(){});
//The following works, but I was hoping there was a better way:
var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice?
Ich bin noch neu dabei, sorry für die Verwirrung.
Vielen Dank!
Wäre es nicht ausreichend, einfach neu zu binden this? var b = c.bind(this, 1,2,3);
– kojiro
13. Dezember 2012 um 0:33 Uhr
Warum ist es problematisch, den ersten Wert von zu haben? bind() sein null? Scheint in FF gut zu funktionieren.
– Russ
13. Dezember 2012 um 0:38 Uhr
Wenn die Funktion diese Grenze bereits hat, wird die Verwendung von null als erstes Argument von bind die Dinge durcheinander bringen (dh eine Objektmethode an den globalen Geltungsbereich binden).
– Durchdringen
13. Dezember 2012 um 0:43 Uhr
Mir ist wirklich unklar, was du vorhast. Du kannst nicht haben this vollständig ungebunden in JavaScript. Es bedeutet immer etwas. Also bindend this zum this der einschließenden Funktion sehr sinnvoll.
– kojiro
13. Dezember 2012 um 1:05 Uhr
Ich bin ziemlich neu bei JS. Ich habe die Frage bearbeitet, um sie klarer zu machen. Es kann sein, dass das, was ich will, nicht möglich ist. Vielen Dank.
– Durchdringen
13. Dezember 2012 um 1:25 Uhr
Sie können dies tun, aber am besten vermeiden Sie es, es als “verbindlich” zu betrachten, da dies der Begriff ist, der zum Festlegen des “this” -Werts verwendet wird. Stellen Sie sich das vielleicht so vor, als würden Sie die Argumente in eine Funktion “verpacken”?
Was Sie tun, ist eine Funktion zu erstellen, in die die gewünschten Argumente über Closures eingebaut sind:
var withWrappedArguments = function(arg1, arg2)
{
return function() { ... do your stuff with arg1 and arg2 ... };
}(actualArg1Value, actualArg2Value);
Ich hoffe, ich habe die Syntax richtig verstanden. Was es tut, ist eine Funktion namens withWrappedArguments() zu erstellen (um pedantisch zu sein, es ist eine anonyme Funktion, die der Variablen zugewiesen ist), die Sie jederzeit und überall aufrufen können und immer mit dem aktuellenArg1Value und dem aktuellenArg2Value und allem anderen, was Sie einfügen möchten, agieren dort. Wenn Sie möchten, können Sie auch weitere Argumente zum Zeitpunkt des Anrufs akzeptieren lassen. Das Geheimnis sind die runden Klammern nach der abschließenden schließenden geschweiften Klammer. Diese bewirken, dass die äußere Funktion mit den übergebenen Werten sofort ausgeführt wird und die später aufrufbare innere Funktion generiert. Die übergebenen Werte werden dann zum Zeitpunkt der Generierung der Funktion eingefroren.
Dies ist effektiv das, was bind tut, aber auf diese Weise ist es explizit, dass die umschlossenen Argumente einfach Closures für lokale Variablen sind, und es besteht keine Notwendigkeit, das Verhalten davon zu ändern.
Beachten Sie, dass dies normalerweise als “Currying” bezeichnet wird.
– M3D
13. September 2017 um 5:17 Uhr
@M3D Großschreibung, die es so komisch aussehen lässt.
– Andreas
5. September 2019 um 19:55 Uhr
Dies wäre viel hilfreicher, wenn ein Beispiel für die Verwendung bereitgestellt würde.
– Andreas
5. September 2019 um 19:57 Uhr
en.wikipedia.org/wiki/Currying Link für alle Interessierten, obwohl die TLDR-Version “statt f(x,y) wir wollen f(x)(y) oder g=f(x); g(y). Also würden wir wechseln f=(x,y)=>x+y zu f=(x)=>(y)=>x+y.”
Wir können also eine Funktion definieren bindArgs das funktioniert wie bindaußer dass nur Argumente gebunden sind, aber nicht der Kontext (this).
Function.prototype.bindArgs =
function (...boundArgs)
{
const targetFunction = this;
return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
};
Dann für eine bestimmte Funktion foo und ein Objekt objdie Aussage
return foo.call(obj, 1, 2, 3, 4);
ist äquivalent zu
let bar = foo.bindArgs(1, 2);
return bar.call(obj, 3, 4);
wo nur das erste und zweite Argument gebunden sind barwährend der Kontext obj der im Aufruf angegebene Wert verwendet wird und zusätzliche Argumente nach den gebundenen Argumenten angehängt werden. Der Rückgabewert wird einfach weitergeleitet.
bringt es6 auf den Tisch, verwendet immer noch var 🙁
– Daniel Köbe
20. November 2016 um 3:47 Uhr
@DanielKobe Danke! Spread-Operatoren und Rest-Parameter wurden schon lange vorher in Firefox implementiert let und const, die noch nicht verfügbar waren, als ich dies zum ersten Mal gepostet habe. Es ist jetzt aktualisiert.
– GOTO 0
20. November 2016 um 8:58 Uhr
Das ist großartig und funktioniert für Callback-Funktionen! Kann auch geändert werden, um Argumente anzuhängen, anstatt sie voranzustellen.
– DenisM
12. August 2017 um 2:09 Uhr
Beachten Sie, dass dies jedes Mal, wenn bindArgs() aufgerufen wird, eine Schließung erzeugt, was bedeutet, dass die Leistung nicht so gut ist wie bei Verwendung der nativen bind()-Funktionalität.
– Joshua Walsh
25. Januar 2019 um 14:17 Uhr
Im Eingeborenen bind Methode das this Wert in der Ergebnisfunktion geht verloren. Sie können das gemeinsame Shim jedoch leicht umcodieren, um kein Argument für den Kontext zu verwenden:
Function.prototype.arg = function() {
if (typeof this !== "function")
throw new TypeError("Function.prototype.arg needs to be called on a function");
var slice = Array.prototype.slice,
args = slice.call(arguments),
fn = this,
partial = function() {
return fn.apply(this, args.concat(slice.call(arguments)));
// ^^^^
};
partial.prototype = Object.create(this.prototype);
return partial;
};
Mag es nicht, dass man mit dem Prototyp von spielen muss Function aber es hat mir viel Zeit und einige hässliche Problemumgehungen gespart. Vielen Dank
– Jackdbernier
19. Mai 2013 um 14:38 Uhr
@jackdbernier: Musst du nicht, aber ich finde es intuitiver als eine Methode wie bind. Sie können es leicht in a umwandeln function bindArgs(fn){ …, args = slice.call(arguments, 1); …}
– Bergi
19. Mai 2013 um 20:03 Uhr
@Qantas94Heavy: Das musst du immer tun, wenn es dir wichtig ist this sein a. Sie könnten verwenden bind stattdessen natürlich. Das OP tut dies jedoch ausdrücklich nicht kümmern sich um die this Wert und wollte eine ungebundene Teilfunktion.
– Bergi
12. Juni 2014 um 12:28 Uhr
@Bergi: Ich war davon ausgegangen, dass der Zweck nicht eingestellt ist this ist, dass die Funktion verwendet this, aber sie wollten es in diesem Moment nicht binden. Auch das Bit in der Frage des OP //These should both have exact same output. steht im Widerspruch zu anderen Teilen davon.
– Qantas 94 Schwer
12. Juni 2014 um 13:18 Uhr
@KubaWyrostek: Ja, es dient dazu, partielle Konstruktorfunktionen zum Laufen zu bringen, ähnlich wie das Erstellen von Unterklassen (allerdings würde ich das nicht empfehlen). Ein tatsächliches bind funktioniert überhaupt nicht mit Konstruktoren, die gebundenen Funktionen haben keine .prototype. Nein, Function.prototype !== mymethod.prototype
– Bergi
22. August 2014 um 14:22 Uhr
Mike
var b = function() {
return c(1,2,3);
};
Eine weitere winzige Implementierung nur zum Spaß:
function bindWithoutThis(cb) {
var bindArgs = Array.prototype.slice.call(arguments, 1);
return function () {
var internalArgs = Array.prototype.slice.call(arguments, 0);
var args = Array.prototype.concat(bindArgs, internalArgs);
return cb.apply(this, args);
};
}
Wie benutzt man:
function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");
Scheint, als wäre es richtiger, “null” dafür zu übergeben, wenn apply() aufgerufen wird.
– Eddiewürde
21. Juni 2017 um 11:18 Uhr
Kevin Ennis
Es ist ein bisschen schwierig, genau zu sagen, was Sie letztendlich tun möchten, da das Beispiel irgendwie willkürlich ist, aber Sie möchten sich vielleicht mit Partials (oder Currying) befassen: http://jsbin.com/ifoqoj/1/edit
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] === undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
var c = function(a, b, c, callback) {
console.log( a, b, c, callback )
};
var b = c.partial(1, 2, 3, undefined);
b(function(){})
Wäre es nicht ausreichend, einfach neu zu binden
this
?var b = c.bind(this, 1,2,3);
– kojiro
13. Dezember 2012 um 0:33 Uhr
Warum ist es problematisch, den ersten Wert von zu haben?
bind()
seinnull
? Scheint in FF gut zu funktionieren.– Russ
13. Dezember 2012 um 0:38 Uhr
Wenn die Funktion diese Grenze bereits hat, wird die Verwendung von null als erstes Argument von bind die Dinge durcheinander bringen (dh eine Objektmethode an den globalen Geltungsbereich binden).
– Durchdringen
13. Dezember 2012 um 0:43 Uhr
Mir ist wirklich unklar, was du vorhast. Du kannst nicht haben
this
vollständig ungebunden in JavaScript. Es bedeutet immer etwas. Also bindendthis
zumthis
der einschließenden Funktion sehr sinnvoll.– kojiro
13. Dezember 2012 um 1:05 Uhr
Ich bin ziemlich neu bei JS. Ich habe die Frage bearbeitet, um sie klarer zu machen. Es kann sein, dass das, was ich will, nicht möglich ist. Vielen Dank.
– Durchdringen
13. Dezember 2012 um 1:25 Uhr