Wie kann man Funktionsargumente binden, ohne dies zu binden?

Lesezeit: 7 Minuten

Benutzer-Avatar
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.”

    – M3D

    7. September 2019 um 0:40 Uhr

Benutzer-Avatar
GOTO 0

In ES6 geht das ganz einfach mit Ruhe Parameter In Verbindung mit Spread-Operator.

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

Benutzer-Avatar
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

Benutzer-Avatar
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(){})

Link zum Artikel von John Resig: http://ejohn.org/blog/partial-functions-in-javascript/

  • Scheint, als wäre es richtiger, “null” dafür zu übergeben, wenn apply() aufgerufen wird.

    – Eddiewürde

    21. Juni 2017 um 11:18 Uhr

Benutzer-Avatar
Daniel Orlando

Verwenden LoDash du kannst den … benutzen _.partial Funktion.

const f  = function (a, b, c, callback) {}

const pf = _.partial(f, 1, 2, 3)  // f has first 3 arguments bound.

pf(function () {})                // callback.

1251950cookie-checkWie kann man Funktionsargumente binden, ohne dies zu binden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy