javascript - Kan du binda 'this' i en pilfunktion?


Jag har experimenterat med ES6 ett tag nu, och jag har just stött på ett litet problem.

Jag gillar verkligen att använda pilfunktioner, och när jag kan, använder jag dem.

Det verkar dock som att du inte kan binda dem!

Här är funktionen:

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

Här är objektet jag vill binda funktionen till:

var o = {'a': 42};

Och här är hur jag skulle binda f till o:

var fBound = f.bind(o);

Och sedan kan jag bara kalla fBound:

fBound();

Vilket kommer att skriva ut detta (objektet o):

{'a': 42}

Cool! Underbart! Förutom att det inte fungerar. Istället för att returnera o-objektet, returnerar det window-objektet.

Så jag skulle vilja veta: kan man binda pilar-funktioner? (Och i så fall, hur?)

Jag har testat koden ovan i Google Chrome 48 och Firefox 43, och resultatet är detsamma.

Svar #1

Du kan inte ändra bindningen av this i en pilfunktion. Den kommer alltid att definieras som den kontext där den definierades. Om du behöver att this ska vara meningsfullt bör du använda en vanlig funktion.

Från ECMAScript 2015-specifikationen:

Alla referenser till arguments, super, this eller new.target inom en ArrowFunction måste lösas till en bindning i en lexikalt omgivande miljö. Vanligtvis kommer detta att vara Funktionsmiljön för en omedelbart omgivande funktion.

Svar #2

För att vara komplett, kan du återbinda pilfunktioner, du kan bara inte ändra betydelsen av this.

bind har fortfarande värde för funktionsargument:

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

Prova det här: http://jsbin.com/motihanopi/edit?js,console

Svar #3

Från MDN:

Ett pilfunktionsuttryck har en kortare syntax jämfört med funktionsuttryck och binder this-värdet lexikalt (binder inte sitt eget this, arguments, super eller new.target). Pilefunktioner är alltid anonyma.

Detta betyder att du inte kan binda ett värde till this som du vill.

Svar #4

beskrivning: Stijn de Witt

Du kan inte använda bind för att ändra värdet av this inuti en pilfunktion. Du kan dock skapa en ny vanlig funktion som gör samma sak som den gamla pilfunktionen och sedan använda call eller bind för att binda om this som vanligt.

Vi använder ett eval-anrop här för att återskapa den pilfunktion du skickar in som en vanlig funktion och sedan använder vi call för att anropa den med ett annat this:

kod: jag

const func = v => console.log(this);
const obj = {value: 10};

function arrowBindOld(context, fn) {
  let arrowFn;
  (function() {
    arrowFn = eval(fn.toString());
    arrowFn();
  }).call(context);
}
arrowBindOld(obj, func);

uppdatera

const f = v => console.log(this, v);
const o = {value: 10};

/* new */
function arrowBind(context, fn) {
  const arrowFnString = fn.toString();
  return (function() {
    return eval(arrowFnString);
  }).call(context);
}
const fBound = arrowBind(o, f);
fBound(10);

/* use prototype */
Function.prototype.arrowBind = function(context) {
  const arrowFnString = this.toString();
  return (function() {
    return eval(arrowFnString);
  }).call(context);
}
const fBoundProto = f.arrowBind(o);
fBoundProto(20);

Relaterade artiklar