Você pode vincular 'this' em uma função de seta?


133

Estou experimentando o ES6 há um tempo e acabei de encontrar um pequeno problema.

Eu realmente gosto de usar as funções de seta e sempre que posso, eu as uso.

No entanto, parece que você não pode vinculá-los!

Aqui está a função:

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

Aqui está o objeto ao qual quero vincular a função:

var o = {'a': 42};

E aqui está como eu me ligaria fa o:

var fBound = f.bind(o);

E então eu posso simplesmente ligar fBound:

fBound();

O que produzirá este (o oobjeto):

{'a': 42}

Legal! Encantador! Exceto que isso não funciona. Em vez de emitir o oobjeto, ele gera o windowobjeto.

Então, eu gostaria de saber: você pode vincular funções de seta? (E se sim, como?)


Testei o código acima no Google Chrome 48 e Firefox 43, e o resultado é o mesmo.


29
O ponto principal das funções das setas é que elas usam o thisescopo pai.
— Loganfsmyth 23/10

Respostas:


158

Você não pode religar this em uma função de seta. Será sempre definido como o contexto em que foi definido. Se você precisar thisser significativo, use uma função normal.

Do ECMAScript 2015 Spec :

Qualquer referência a argumentos, super, this ou new.target em um ArrowFunction deve resolver uma ligação em um ambiente que inclua lexicamente. Normalmente, este será o ambiente de funções de uma função que encerra imediatamente.


7
A primeira frase desta resposta está errada. Provavelmente porque a questão também é confusa e vinculativa this. Os dois estão relacionados, mas não são os mesmos. thisdentro de uma função de seta sempre 'herda' o thisdo escopo. Essa é uma característica das funções de seta. Mas você ainda pode bindtodos os outros parâmetros de uma função de seta. Apenas não this.
— Stijn de Witt

54

Para concluir, você pode reconectar as funções das setas, apenas não pode alterar o significado de this.

bind ainda tem valor para argumentos da função:

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

Experimente aqui: http://jsbin.com/motihanopi/edit?js,console


1
Existe uma maneira de detectar ou usar qualquer objeto ao qual a função (seta) esteja vinculada, sem fazer referência this(que é, obviamente, definida lexicamente)?
— Florrie

3
Use um argumento para o contexto: ((context) => {someOtherFunction.apply (context)}). Bind (willBeIgnored, context) () #
— 276 cvazac

13

Do MDN :

Uma expressão de função de seta possui uma sintaxe mais curta em comparação com as expressões de função e vincula lexicamente o valor this (não vincula seus argumentos this, argumentos, super ou new.target). As funções de seta são sempre anônimas.

Isso significa que você não pode vincular um valor thiscomo desejar.


6

Por anos, os desenvolvedores do js lutaram com a vinculação de contexto, perguntaram por que thismudaram no javascript, tanta confusão ao longo dos anos devido à vinculação de contexto e a diferença entre o significado de thisjavascript e thisna maioria das outras linguagens OOP.

Tudo isso me leva a perguntar, por que, por que! por que você não queria reativar uma função de seta! Aqueles onde criado especialmente para resolver todos estes problemas e confusões e evitar ter que usar bindou callou qualquer outra forma de preservar o escopo da função.

TL; DR

Não, você não pode religar as funções de seta.


7
As funções de seta foram criadas antes de tudo para fornecer uma sintaxe mais limpa e rápida. Pense no cálculo lambda. Pena que os fanáticos por OO que importunam a vida de programadores JS funcionais aproveitaram a oportunidade para tirar a liberdade de especificar o contexto de chamada.
— Marco Faustinelli

5
Usar thisnão é funcional. lambdas deve ser arguments => output. Se você precisar de algum contexto externo, transmita-o. A própria existência disso thisé o que facilitou toda a manutenção de padrões OO na linguagem. Você nunca teria ouvido o termo "classe javascript" sem ele.
— erich2k8

3
Você pode religar as funções de seta. Apenas não this.
— Stijn de Witt

6

Você não pode bindalterar o valor de thisdentro de uma função de seta. No entanto, você pode criar uma nova função regular que faça a mesma coisa que a seta antiga e, em seguida, use callou bindpara reconfigurar thisnormalmente.

Usamos uma evalchamada aqui para recriar a função de seta que você passa como uma função normal e, em seguida, usa-a callpara invocá-la com uma função 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)});


3
Obrigado por compartilhar este exemplo de uma maneira de vincular uma função de seta a um contexto diferente! Para facilitar a resposta dos futuros leitores, talvez você possa editá- la para descrever como e por que o código funciona?
— Florrie

4

As funções de seta do ES6 realmente resolvem "isso" em JavaScript

O link acima explica que as funções das setas thisnão mudam com as bind, call, applyfunções.

É explicado com um exemplo muito bom.

execute isso node v4para ver o comportamento "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(); 

Solicitar que você forneça informações mais relevantes na própria resposta, pode ser um código de exemplo ou versões editadas de perguntas
— jithin Scaria

// execute isso no nó v4 para ver o comportamento "esperado" this.test = "anexado ao módulo"; var foo = {test: "anexado a um objeto"}; foo.method = function (name, cb) {// vincula o valor "this" no método // para tentar forçá-lo a ser o que você deseja this [name] = cb.bind (this); }; foo.method ("bar", () => {console.log (this.test);}); foo.bar ();
— Prithvi Raj Vuppalapati 02/07

O interessante aqui é tentar fazer isso e tentar novamente substituindo foo.method ('bar', () => {console.log (this.test);}); com foo.method ('bar', function () {console.log (this.test);}); - os logs da primeira versão "anexados ao módulo" e os segundos logs "anexados ao objeto" - eu realmente prefiro o tratamento mais estável de "this" usando as funções de seta. Você ainda pode obter os outros efeitos usando padrões diferentes e os resultados são IMO mais legíveis e previsíveis.
— Methodician


2

Resumindo, você NÃO pode vincular funções de seta, mas continue lendo:

Imagine que você tem esta função de seta abaixo da qual é impressa thisno console:

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

Portanto, a solução rápida para isso seria usar a função normal, então altere-a para:

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

Em seguida, você pode vinculá-lo a qualquer ambiente lexical usando bindou callou apply:

const bindedFunc = myFunc.bind(this);

e chamá-lo em caso de bind.

bindedFunc();

Também existem maneiras de usá eval()-lo, o que não é recomendado .


function myFuncé comportamentalmente diferente, além de ser vinculável; uma correspondência mais próxima seria const myFunc = function() {...}. Também estou curioso sobre o que você quer dizer com eval, já que essa é uma abordagem que acho que nenhuma resposta já foi compartilhada aqui antes - seria interessante ver como isso é feito e depois ler por que é tão fortemente desencorajado.
— Florrie 21/01

1

Talvez este exemplo ajude você:

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


coisas boas ... levemente interessante
— Aleks
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.