Puoi associare "questo" a una funzione freccia?


133

Sto sperimentando ES6 da un po 'di tempo e ho appena riscontrato un leggero problema.

Mi piace molto usare le funzioni freccia e ogni volta che posso, le uso.

Tuttavia, sembrerebbe che non puoi vincolarli!

Ecco la funzione:

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

Ecco l'oggetto a cui voglio associare la funzione:

var o = {'a': 42};

Ed ecco come mi legherei fa o:

var fBound = f.bind(o);

E poi posso semplicemente chiamare fBound:

fBound();

Che produrrà questo (l' ooggetto):

{'a': 42}

Freddo! Bello! Solo che non funziona. Invece di emettere l' ooggetto, genera l' windowoggetto.

Quindi vorrei sapere: puoi associare le funzioni freccia? (E se sì, come?)


Ho testato il codice sopra in Google Chrome 48 e Firefox 43 e il risultato è lo stesso.


29
L'intero punto delle funzioni freccia è che usano il thisloro ambito genitore.
loganfsmyth,

Risposte:


158

Non è possibile ricollegare this in una funzione freccia. Sarà sempre definito come il contesto in cui è stato definito. Se devi thisessere significativo, dovresti usare una normale funzione.

Dalle specifiche ECMAScript 2015 :

Qualsiasi riferimento ad argomenti, super, this o new.target all'interno di una ArrowFunction deve risolversi in un'associazione in un ambiente lessicale. In genere questo sarà l'ambiente funzionale di una funzione che si chiude immediatamente.


7
La prima frase di questa risposta è sbagliata. Probabilmente perché la domanda è anche confusa vincolante e this. I due sono correlati, ma non uguali. thisall'interno di una funzione freccia 'eredita' sempre thisl'ambito compreso. Questa è una caratteristica delle funzioni freccia. Ma puoi ancora bindtutti gli altri parametri di una funzione freccia. Proprio no this.
Stijn de Witt,

54

Per essere completo, è possibile ricollegare le funzioni delle frecce, semplicemente non è possibile modificare il significato di this.

bind ha ancora valore per gli argomenti della funzione:

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

Provalo qui: http://jsbin.com/motihanopi/edit?js,console


1
Esiste un modo per rilevare o utilizzare qualsiasi oggetto a cui è associata la funzione (freccia), senza fare riferimento this(che, ovviamente, è definito in modo lessicale)?
Florrie,

3
Usa un argomento per context: ((context) => {someOtherFunction.apply (context)}). Bind (willBeIgnored, context) ()
cvazac

13

Dal MDN :

Un'espressione di funzione freccia ha una sintassi più breve rispetto alle espressioni di funzione e associa in modo lessicale questo valore (non associa a sé questo, argomenti, super o new.target). Le funzioni freccia sono sempre anonime.

Ciò significa che non puoi associare un valore a thisquello che desideri.


6

Per anni, gli sviluppatori di js hanno lottato con l'associazione del contesto, chiedendosi perché è thiscambiato in javascript, tanta confusione negli anni a causa dell'associazione del contesto e la differenza tra il significato di thisin javascript e thisnella maggior parte degli altri linguaggi OOP.

Tutto ciò mi porta a chiedere, perché, perché! perché non vorresti ricollegare una funzione freccia! Quelli in cui appositamente creato per risolvere tutti questi problemi e confusioni ed evitare di dover utilizzare bindo callo qualsiasi altro modo per preservare la portata della funzione.

TL; DR

No, non è possibile ricollegare le funzioni delle frecce.


7
Le funzioni freccia sono state create prima di tutto per fornire una sintassi più pulita e veloce. Pensa al lambda-calcolo. Peccato che i fanatici OO che infastidiscono la vita dei programmatori JS funzionali abbiano colto l'occasione per togliere la libertà di specificare il contesto di invocazione.
Marco Faustinelli,

5
L'uso thisnon è funzionale. lambdas dovrebbe essere arguments => output. Se hai bisogno di un contesto esterno, passalo dentro. L'esistenza stessa thisè ciò che ha facilitato tutte le scarpate dei modelli OO nella lingua. Non avresti mai sentito il termine "classe JavaScript" senza di essa.
erich2k8,

3
È possibile ricollegare le funzioni delle frecce. Proprio no this.
Stijn de Witt,

6

Non è possibile utilizzare bindper modificare il valore thisall'interno di una funzione freccia. Tuttavia, è possibile creare una nuova funzione regolare che fa la stessa cosa della vecchia funzione freccia e quindi utilizzare callo bindper ricollegare thiscome di consueto.

Usiamo una evalchiamata qui per ricreare la funzione freccia che passi come una normale funzione e quindi usiamo callper invocarla con una diversa this:

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


3
Grazie per aver condiviso questo esempio di un modo per associare una funzione freccia a un contesto diverso! Per rendere la risposta più facile da comprendere per i futuri lettori, forse potresti modificarla per descrivere come e perché il codice funziona?
Florrie,

4

Le funzioni della freccia ES6 risolvono davvero "questo" in JavaScript

Il link sopra spiega che le funzioni freccia thisnon cambiano con le bind, call, applyfunzioni.

Viene spiegato con un bell'esempio.

eseguilo node v4per vedere il comportamento "previsto",

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(); 

Richiesta di fornire informazioni più pertinenti nella risposta stessa, può essere un codice di esempio o versioni modificate delle domande
Jithin Scaria,

// esegui questo nel nodo v4 per vedere il comportamento "previsto" this.test = "attaccato al modulo"; var foo = {test: "attaccato a un oggetto"}; foo.method = function (name, cb) {// associa il valore di "this" al metodo // per provare a forzarlo ad essere quello che vuoi this [name] = cb.bind (this); }; foo.method ("bar", () => {console.log (this.test);}); foo.bar ();
Prithvi Raj Vuppalapati,

La cosa interessante qui è provare questo e poi riprovare sostituendo foo.method ('bar', () => {console.log (this.test);}); con foo.method ('bar', function () {console.log (this.test);}); - i registri della prima versione "collegati al modulo" e i secondi registri "collegati a un oggetto" - Preferisco davvero il trattamento più stabile di "questo" utilizzando le funzioni freccia. Puoi comunque ottenere gli altri effetti usando diversi pattern e i risultati sono IMO più leggibili e prevedibili.
Metodista


2

In breve, NON PUOI legare le funzioni della freccia, ma continua a leggere:

Immagina di avere questa funzione freccia sotto la quale stampa thissulla console:

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

Quindi la soluzione rapida per questo sarebbe usare la normale funzione, quindi basta cambiarla in:

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

Quindi puoi associarlo a qualsiasi ambiente lessicale usando bindo callo apply:

const bindedFunc = myFunc.bind(this);

e chiamalo in caso di bind.

bindedFunc();

Ci sono anche modi per usarlo eval()per farlo, che fortemente sconsigliato .


function myFuncè diverso dal punto di vista comportamentale oltre a essere vincolante; sarebbe una partita più vicina const myFunc = function() {...}. Sono anche curioso di sapere cosa intendi usando eval, dato che si tratta di un approccio che non credo abbia condiviso nessuna risposta qui prima: sarebbe interessante vedere come è stato fatto e poi leggere perché è così fortemente scoraggiato.
Florrie,

1

Forse questo esempio ti aiuta:

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();


cose roba ... lievemente intérésting
Aleks
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.