¿Se puede vincular 'esto' en una función de flecha?

133

He estado experimentando con ES6 durante un tiempo y acabo de encontrar un pequeño problema.

Realmente me gusta usar las funciones de flecha, y siempre que puedo, las uso.

Sin embargo, ¡parece que no puedes atarlos!

Aquí está la función:

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

Aquí está el objeto al que quiero vincular la función:

var o = {'a': 42};

Y así es como me uniría fa o:

var fBound = f.bind(o);

Y luego solo puedo llamar fBound:

fBound();

Lo que generará esto (el oobjeto):

{'a': 42}

¡Frio! ¡Encantador! Excepto que no funciona. En lugar de generar el oobjeto, genera el windowobjeto.

Entonces me gustaría saber: ¿puedes unir las funciones de flecha? (Y si es así, ¿cómo?)


He probado el código anterior en Google Chrome 48 y Firefox 43, y el resultado es el mismo.

Florrie
fuente
29
Todo el punto de las funciones de flecha es que usan el thisde su ámbito principal.
loganfsmyth

Respuestas:

158

No puede volver this a vincular en una función de flecha. Siempre se definirá como el contexto en el que se definió. Si necesita thisser significativo, debe usar una función normal.

De la especificación ECMAScript 2015 :

Cualquier referencia a argumentos, super, this o new.target dentro de una función de flecha debe resolver un enlace en un entorno léxico. Normalmente, este será el entorno de función de una función de cierre inmediato.

Nick Tomlin
fuente
77
La primera oración de esta respuesta es incorrecta. Probablemente porque la pregunta también es confusa y vinculante this. Los dos están relacionados, pero no son lo mismo. thisdentro de una función de flecha siempre 'hereda' el thisdel ámbito de inclusión. Esa es una característica de las funciones de flecha. Pero aún puede bindtodos los demás parámetros de una función de flecha. Solo que no this.
Stijn de Witt
54

Para completar, puede volver a vincular las funciones de flecha, simplemente no puede cambiar el significado de this.

bind todavía tiene valor para argumentos de función:

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

Pruébelo aquí: http://jsbin.com/motihanopi/edit?js,console

cvazac
fuente
1
¿Hay alguna manera de detectar o usar cualquier objeto al que esté vinculada la función (flecha), sin hacer referencia this(que, por supuesto, se define léxicamente)?
Florrie
3
Utilice un argumento para el contexto: ((context) => {someOtherFunction.apply (context)}). Bind (willBeIgnored, context) ()
cvazac
13

Desde el MDN :

Una expresión de función de flecha tiene una sintaxis más corta en comparación con las expresiones de función y enlaza léxicamente el valor this (no enlaza sus propios this, argumentos, super o new.target). Las funciones de flecha son siempre anónimas.

Esto significa que no puede vincular un valor que thisle guste.

Sterling Archer
fuente
6

Durante años, los desarrolladores de js lucharon con el enlace de contexto, preguntaron por qué thiscambió en javascript, tanta confusión a lo largo de los años debido al enlace de contexto y la diferencia entre el significado de thisen javascript y thisen la mayoría de los otros lenguajes OOP.

¡Todo esto me lleva a preguntar, por qué, por qué! ¿Por qué no quieres volver a vincular una función de flecha? Aquellos en los que especialmente creado para resolver todos estos problemas y confusiones y evitar tener que utilizar bindo callo cualquier otra forma de preservar el ámbito de la función.

TL; DR

No, no puede volver a vincular las funciones de flecha.

taxicala
fuente
77
Las funciones de flecha se crearon en primer lugar para proporcionar una sintaxis más limpia y rápida. Piensa en el cálculo lambda. Lástima que los fanáticos OO que molestan la vida de los programadores JS funcionales aprovecharon la oportunidad para quitarles la libertad de especificar el contexto de invocación.
Marco Faustinelli
55
Usar thisno es funcional. Las lambdas deberían ser arguments => output. Si necesita algún contexto externo, páselo. La existencia misma de thises lo que facilitó todo el calce de los patrones OO en el lenguaje. Nunca habrías escuchado el término "clase javascript" sin él.
erich2k8
3
Usted puede volver a enlazar las funciones de dirección. Solo que no this.
Stijn de Witt
6

No puede usar bindpara cambiar el valor de thisdentro de una función de flecha. Sin embargo, puede crear una nueva función regular que haga lo mismo que la función de flecha anterior y luego usar callo bindvolver a enlazar thiscomo de costumbre.

Usamos una evalllamada aquí para recrear la función de flecha que pasas como una función normal y luego usamos callpara invocarla con un diferente this:

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

el nombre
fuente
3
¡Gracias por compartir este ejemplo de una forma de vincular una función de flecha a un contexto diferente! Para facilitar la comprensión de los futuros lectores, ¿tal vez podría editarla para describir cómo y por qué funciona el código?
Florrie
4

¿Las funciones de flecha ES6 realmente resuelven "esto" en JavaScript

El enlace anterior explica que las funciones de flecha this no cambian con las bind, call, applyfunciones.

Se explica con un muy buen ejemplo.

ejecuta esto node v4para ver el comportamiento "esperado",

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
fuente
Solicitarle que brinde información más relevante en la propia respuesta, puede ser un código de muestra o versiones editadas de preguntas
Jithin Scaria
// ejecuta esto en el nodo v4 para ver el comportamiento "esperado" this.test = "adjunto al módulo"; var foo = {prueba: "adjunto a un objeto"}; foo.method = function (name, cb) {// enlaza el valor de "this" en el método // para intentar forzar que sea lo que quieres this [name] = cb.bind (this); }; foo.method ("bar", () => {console.log (this.test);}); foo.bar ();
Prithvi Raj Vuppalapati
Lo interesante aquí es probar esto y luego intentarlo nuevamente reemplazando foo.method ('bar', () => {console.log (this.test);}); con foo.method ('bar', function () {console.log (this.test);}); - la primera versión registra "adjunta al módulo" y la segunda registra "adjunta al objeto" - Realmente prefiero el tratamiento más estable de "esto" utilizando las funciones de flecha. Todavía puede lograr los otros efectos usando diferentes patrones y los resultados son más legibles y predecibles IMO.
Metodista el
3

Hice la misma pregunta hace un par de días.

No puede enlazar un valor ya que el thisya está enlazado.

Enlace diferente de este ámbito a ES6 => operador de función

fos.alex
fuente
44
"ya que esto ya thisestá enlazado " - En las funciones regulares también está enlazado. El punto es que en las funciones de flecha no tiene enlace local .
un mejor Oliver
2

Corto, NO PUEDES enlazar funciones de flecha, pero siga leyendo:

Imagine que tiene esta función de flecha debajo que se imprime thisen la consola:

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

Entonces, la solución rápida para esto sería usar la función normal, así que cámbielo a:

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

Luego puede vincularlo a cualquier entorno léxico usando bindo callo apply:

const bindedFunc = myFunc.bind(this);

y llamarlo en caso de bind.

bindedFunc();

También hay formas de usar eval()para hacerlo, lo que no es muy recomendable .

Alireza
fuente
function myFunces conductualmente diferente en formas además de ser vinculable; una aproximación más exacta sería const myFunc = function() {...}. También tengo curiosidad por lo que quieres decir con evaluar, ya que ese es un enfoque que no creo que haya compartido ninguna respuesta aquí antes; sería interesante ver cómo se hace y luego leer por qué está tan desaconsejado.
Florrie
1

Tal vez este ejemplo te ayude:

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
fuente
cosas de gøød ... ligeramente intérésting
Aleks