Können Sie 'dies' in einer Pfeilfunktion binden?

133

Ich habe jetzt eine Weile mit ES6 experimentiert und bin gerade auf ein kleines Problem gestoßen.

Ich benutze sehr gerne Pfeilfunktionen und wann immer ich kann, benutze ich sie.

Es scheint jedoch, dass Sie sie nicht binden können!

Hier ist die Funktion:

var f = () => console.log(this);

Hier ist das Objekt, an das ich die Funktion binden möchte:

var o = {'a': 42};

Und hier ist , wie ich binden fan o:

var fBound = f.bind(o);

Und dann kann ich einfach anrufen fBound:

fBound();

Welches wird dies (das oObjekt) ausgeben :

{'a': 42}

Cool! Schön! Nur dass es nicht funktioniert. Anstatt das oObjekt auszugeben, wird das Objekt ausgegeben window.

Ich würde gerne wissen: Können Sie Pfeilfunktionen binden? (Und wenn ja, wie?)


Ich habe den obigen Code in Google Chrome 48 und Firefox 43 getestet und das Ergebnis ist das gleiche.

Florrie
quelle
29
Die ganze Funktion der Pfeilspitzen besteht darin, dass sie den thisübergeordneten Bereich verwenden.
Loganfsmyth

Antworten:

158

Sie können eine Pfeilfunktion nicht erneut bindenthis . Es wird immer als der Kontext definiert, in dem es definiert wurde. Wenn Sie thisaussagekräftig sein möchten, sollten Sie eine normale Funktion verwenden.

Aus der ECMAScript 2015-Spezifikation :

Jeder Verweis auf Argumente, super, this oder new.target innerhalb einer ArrowFunction muss in eine Bindung in einer lexikalisch einschließenden Umgebung aufgelöst werden. In der Regel ist dies die Funktionsumgebung einer unmittelbar einschließenden Funktion.

Nick Tomlin
quelle
7
Der erste Satz dieser Antwort ist falsch. Wahrscheinlich, weil die Frage auch verwirrend bindend ist und this. Die beiden sind verwandt, aber nicht gleich. thisInnerhalb einer Pfeilfunktion "erbt" die Funktion immer thisvom umschließenden Bereich. Das ist ein Merkmal von Pfeilfunktionen. Sie können aber noch bindalle anderen Parameter einer Pfeilfunktion verwenden. Nur nicht this.
Stijn de Witt
54

Um vollständig zu sein, können Sie die Pfeilfunktionen neu binden und die Bedeutung von einfach nicht ändern this.

bind hat noch Wert für Funktionsargumente:

((a, b, c) => {
  console.info(a, b, c) // 1, 2, 3
}).bind(undefined, 1, 2, 3)()

Probieren Sie es hier aus: http://jsbin.com/motihanopi/edit?js,console

cvazac
quelle
1
Gibt es eine Möglichkeit, ein Objekt zu erkennen oder zu verwenden, an das die (Pfeil-) Funktion gebunden ist, ohne darauf zu verweisen this(was natürlich lexikalisch definiert ist)?
Florrie
3
Verwenden Sie ein Argument für den Kontext: ((context) => {someOtherFunction.apply (context)}). Bind (willBeIgnored, context) ()
cvazac
13

Aus dem MDN :

Ein Pfeilfunktionsausdruck hat eine kürzere Syntax als Funktionsausdrücke und bindet diesen Wert lexikalisch (bindet nicht seinen eigenen Wert this, arguments, super oder new.target). Pfeilfunktionen sind immer anonym.

Dies bedeutet, dass Sie einen Wert nicht an einen thisgewünschten Wert binden können .

Sterling Archer
quelle
6

Jahrelang hatten js-Entwickler Probleme mit der Kontextbindung und fragten, warum thissich Javascript geändert habe, was im Laufe der Jahre aufgrund der Kontextbindung und des Unterschieds zwischen der Bedeutung von thisJavascript und den thismeisten anderen OOP-Sprachen zu großer Verwirrung geführt habe .

All dies führt mich zu der Frage, warum, warum! Warum sollten Sie eine Pfeilfunktion nicht erneut binden? Diese wurden speziell entwickelt, um all diese Probleme und Verwirrungen zu lösen und zu vermeiden, dass der Funktionsumfang verwendet werden muss bindoder auf callandere Weise.

TL; DR

Nein, Sie können Pfeilfunktionen nicht neu binden.

taxicala
quelle
7
Zuallererst wurden Pfeilfunktionen erstellt, um eine sauberere und schnellere Syntax bereitzustellen. Denken Sie an Lambda-Kalkül. Schade, dass die OO-Eiferer, die das Leben funktionaler JS-Programmierer belasten, die Gelegenheit ergriffen haben, die Freiheit zu nehmen, den Aufrufkontext anzugeben.
Marco Faustinelli
5
Verwenden thisist nicht funktionsfähig. Lambdas sollten sein arguments => output. Wenn Sie einen externen Kontext benötigen, geben Sie ihn weiter. Die bloße Existenz von thishat den gesamten Einstieg in die Sprache erleichtert. Ohne ihn hätten Sie den Begriff "Javascript-Klasse" nie gehört.
erich2k8
3
Sie können Pfeilfunktionen neu binden. Nur nicht this.
Stijn de Witt
5

Sie können bindden Wert thisinnerhalb einer Pfeilfunktion nicht ändern . Sie können jedoch eine neue reguläre Funktion erstellen, die das Gleiche wie die alte Pfeilfunktion tut, und dann wie gewohnt verwenden calloder bindneu binden this.

Wir verwenden hier einen evalAufruf, um die Pfeilfunktion, die Sie als normale Funktion übergeben, neu zu erstellen und sie dann callmit einer anderen Funktion aufzurufen this:

var obj = {value: 10};
function arrowBind(context, fn) {
  let arrowFn;
  (function() {
    arrowFn = eval(fn.toString());
    arrowFn();
  }).call(context);
}
arrowBind(obj, () => {console.log(this)});

der Name
quelle
3
Vielen Dank, dass Sie dieses Beispiel für die Bindung einer Pfeilfunktion an einen anderen Kontext geteilt haben! Um die Antwort für zukünftige Leser leichter verständlich zu machen, können Sie sie möglicherweise bearbeiten , um zu beschreiben, wie und warum der Code funktioniert.
Florrie
4

Lösen Sie ES6-Pfeilfunktionen wirklich "dies" in JavaScript

Der obige Link erklärt, dass sich die Pfeilfunktionen thisnicht mit den bind, call, applyFunktionen ändern .

Es wird mit einem sehr schönen Beispiel erklärt.

Führen Sie dies aus node v4, um das "erwartete" Verhalten zu sehen.

this.test = "attached to the module";
var foo = { test: "attached to an object" };
foo.method = function(name, cb){ 
    // bind the value of "this" on the method 
    // to try and force it to be what you want 
    this[name] = cb.bind(this); };
foo.method("bar", () => { console.log(this.test); });
foo.bar(); 
Prithvi Raj Vuppalapati
quelle
Bitten Sie Sie, relevantere Informationen in der Antwort selbst
anzugeben. Dies
// führe dies in Knoten v4 aus, um das "erwartete" Verhalten zu sehen this.test = "an das Modul angehängt"; var foo = {test: "an ein Objekt angehängt"}; foo.method = function (name, cb) {// binde den Wert von "this" an die Methode //, um zu versuchen, ihn so zu erzwingen, wie du willst. this [name] = cb.bind (this); }; foo.method ("bar", () => {console.log (this.test);}); foo.bar ();
Prithvi Raj Vuppalapati
Interessant ist hier, dies zu versuchen und es dann erneut zu versuchen, indem foo.method ('bar', () => {console.log (this.test);}) ersetzt wird. mit foo.method ('bar', function () {console.log (this.test);}); - Die Protokolle der ersten Version "an das Modul angehängt" und die zweiten Protokolle "an ein Objekt angehängt" - Ich bevorzuge wirklich die stabilere Behandlung von "dies" mit Pfeilfunktionen. Sie können die anderen Effekte immer noch mit unterschiedlichen Mustern erzielen und die Ergebnisse sind IMO besser lesbar und vorhersehbar.
Methodiker
2

Kurz gesagt, Sie können keine Pfeilfunktionen binden, aber lesen Sie weiter:

Stellen Sie sich vor, Sie haben diese Pfeilfunktion, unter der thisauf der Konsole gedruckt wird:

const myFunc = ()=> console.log(this);

Die schnelle Lösung hierfür wäre die Verwendung der normalen Funktion. Ändern Sie sie einfach in:

function myFunc() {console.log(this)};

Dann können Sie es mit bindoder calloder an jede lexikalische Umgebung binden apply:

const bindedFunc = myFunc.bind(this);

und nenne es im Falle von bind.

bindedFunc();

Es gibt auch Möglichkeiten, dies eval()zu tun, was dringend nicht empfohlen wird .

Alireza
quelle
function myFuncist verhaltensmäßig anders als bindbar; ein engeres Spiel wäre const myFunc = function() {...}. Ich bin auch neugierig, was Sie mit eval meinen, da dies ein Ansatz ist, von dem ich glaube, dass hier noch keine Antworten geteilt wurden. Es wäre interessant zu sehen, wie das gemacht wird, und dann zu lesen, warum es so stark entmutigt ist.
Florrie
1

Vielleicht hilft Ihnen dieses Beispiel:

let bob = {
   _name: "Bob",
   _friends: ["stackoverflow"],
   printFriends:(x)=> {
      x._friends.forEach((f)=> {
         console.log(x._name + " knows " + f);
      });
   }
}

bob.printFriends = (bob.printFriends).bind(null,bob);
bob.printFriends();

Ehsan
quelle
gøød stuff ... mild intérésting
Aleks