Eu tenho uma função construtora que registra um manipulador de eventos:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
No entanto, não consigo acessar a data
propriedade do objeto criado dentro do retorno de chamada. Parece que this
não se refere ao objeto que foi criado, mas a outro.
Eu também tentei usar um método de objeto em vez de uma função anônima:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
mas exibe os mesmos problemas.
Como posso acessar o objeto correto?
javascript
callback
this
Felix Kling
fonte
fonte
Respostas:
O que você deve saber sobre
this
this
(também conhecido como "o contexto") é uma palavra-chave especial dentro de cada função e seu valor depende apenas de como a função foi chamada, não de como / quando / onde foi definida. Não é afetado por escopos lexicais como outras variáveis (exceto para funções de seta, veja abaixo). aqui estão alguns exemplos:Para saber mais
this
, consulte a documentação do MDN .Como se referir ao correto
this
Não use
this
Você realmente não deseja acessar
this
em particular, mas o objeto a que se refere . É por isso que uma solução fácil é simplesmente criar uma nova variável que também se refere a esse objeto. A variável pode ter qualquer nome, mas os comuns sãoself
ethat
.Como
self
é uma variável normal, ela obedece às regras de escopo lexical e é acessível dentro do retorno de chamada. Isso também tem a vantagem de poder acessar othis
valor do retorno de chamada.Conjunto explicitamente
this
do retorno de chamada - parte 1Pode parecer que você não tem controle sobre o valor de
this
porque seu valor é definido automaticamente, mas esse não é realmente o caso.Toda função possui o método
.bind
[docs] , que retorna uma nova funçãothis
vinculada a um valor. A função tem exatamente o mesmo comportamento que você chamou.bind
, apenas quethis
foi definido por você. Não importa como ou quando essa função é chamada,this
sempre se refere ao valor passado.Nesse caso, estamos vinculando os retornos de chamada
this
ao valor deMyConstructor
'sthis
.Nota: Ao vincular o contexto para jQuery, use
jQuery.proxy
[docs] . O motivo para fazer isso é que você não precisa armazenar a referência à função ao desvincular um retorno de chamada de evento. O jQuery lida com isso internamente.ECMAScript 6: Usar funções de seta
O ECMAScript 6 apresenta funções de seta , que podem ser consideradas funções lambda. Eles não têm sua própria
this
ligação. Em vez disso,this
é pesquisado no escopo como uma variável normal. Isso significa que você não precisa ligar.bind
. Esse não é o único comportamento especial que eles têm; consulte a documentação do MDN para obter mais informações.Conjunto
this
do retorno de chamada - parte 2Algumas funções / métodos que aceitam retornos de chamada também aceitam um valor ao qual os retornos de chamada
this
devem se referir. Isso é basicamente o mesmo que vincular você mesmo, mas a função / método faz isso por você.Array#map
[docs] é esse método. Sua assinatura é:O primeiro argumento é o retorno de chamada e o segundo argumento é o valor ao qual
this
deve se referir. Aqui está um exemplo artificial:Nota: Se você pode ou não passar um valor
this
geralmente é mencionado na documentação dessa função / método. Por exemplo, o$.ajax
método do jQuery [docs] descreve uma opção chamadacontext
:Problema comum: Usando métodos de objeto como retornos de chamada / manipuladores de eventos
Outra manifestação comum desse problema é quando um método de objeto é usado como manipulador de retorno de chamada / evento. Funções são cidadãos de primeira classe em JavaScript e o termo "método" é apenas um termo coloquial para uma função que é um valor de uma propriedade de objeto. Mas essa função não tem um link específico para seu objeto "contendo".
Considere o seguinte exemplo:
A função
this.method
é atribuída como manipulador de eventos de clique, mas sedocument.body
for clicado, o valor registrado seráundefined
, porque dentro do manipulador de eventosthis
se refere àdocument.body
instância, e não à instânciaFoo
.Como já mencionado no início, o que
this
se refere depende de como a função é chamada , não de como é definida .Se o código fosse o seguinte, pode ser mais óbvio que a função não tenha uma referência implícita ao objeto:
A solução é a mesma mencionada acima: Se disponível, use
.bind
para ligar explicitamentethis
a um valor específicoou chame explicitamente a função como um "método" do objeto, usando uma função anônima como retorno de chamada / manipulador de eventos e atribua o objeto (
this
) a outra variável:ou use uma função de seta:
fonte
self
ethat
para se referiremthis
. Eu me sinto assim porquethis
é uma variável sobrecarregada usada em diferentes contextos; enquanto queself
geralmente corresponde à instância local ethat
geralmente se refere a outro objeto. Sei que você não definiu essa regra, pois já a vi aparecer em vários outros lugares, mas também é por isso que comecei a usá-la_this
, mas não tenho certeza de como os outros se sentem, exceto pela prática não uniforme. isso resultou.Function.prototype.call ()
eFunction.prototype.apply ()
. Particularmente,apply ()
eu tenho muita quilometragem. Estou menos inclinado a usarbind ()
talvez apenas por hábito, embora esteja ciente (mas não certo) de que possa haver pequenas vantagens gerais em usar o bind sobre as outras opções.() => this.clicked()
;)Aqui estão várias maneiras de acessar o contexto pai dentro do contexto filho -
bind()
função1. Use a
bind()
funçãoSe você estiver usando
underscore.js
- http://underscorejs.org/#bind2 Armazene a referência ao contexto / isto dentro de outra variável
Função de 3 setas
fonte
Está tudo na sintaxe "mágica" de chamar um método:
Quando você obtém a propriedade do objeto e a chama de uma só vez, o objeto será o contexto do método. Se você chamar o mesmo método, mas em etapas separadas, o contexto será o escopo global (janela):
Quando você obtém a referência de um método, ele não está mais anexado ao objeto, é apenas uma referência a uma função simples. O mesmo acontece quando você obtém a referência para usar como retorno de chamada:
É aí que você vincula o contexto à função:
Se você estiver usando jQuery, deverá usar o
$.proxy
método, poisbind
não é suportado em todos os navegadores:fonte
O problema com o "contexto"
O termo "contexto" às vezes é usado para se referir ao objeto referenciado por isso . Seu uso é inadequado, porque não se encaixa tanto semanticamente ou tecnicamente com ECMAScript do presente .
"Contexto" significa as circunstâncias que envolvem algo que adiciona significado, ou algumas informações anteriores e posteriores que dão significado extra. O termo "contexto" é usado no ECMAScript para se referir ao contexto de execução , que é todos os parâmetros, escopo e isso dentro do escopo de algum código em execução.
Isso é mostrado na seção 10.4.2 do ECMA-262 :
o que indica claramente que isso faz parte de um contexto de execução.
Um contexto de execução fornece as informações circundantes que adicionam significado ao código que está sendo executado. Inclui muito mais informações do que apenas thisBinding .
Portanto, o valor disso não é "contexto", é apenas uma parte de um contexto de execução. É essencialmente uma variável local que pode ser definida pela chamada para qualquer objeto e, no modo estrito, para qualquer valor.
fonte
this
mas nenhum é oferecido aqui, e é provavelmente muito tarde para fechar a porta no "contexto".Você deve saber sobre "esta" palavra-chave.
De acordo com minha opinião, você pode implementar "isso" de três maneiras (função Self / Arrow / Bind Method)
A palavra-chave de uma função se comporta de maneira um pouco diferente no JavaScript em comparação com outros idiomas.
Também possui algumas diferenças entre o modo estrito e o modo não estrito.
Na maioria dos casos, o valor disso é determinado pela maneira como uma função é chamada.
Ele não pode ser definido por atribuição durante a execução e pode ser diferente cada vez que a função é chamada.
O ES5 introduziu o método bind () para definir o valor de uma função, independentemente de como é chamada,
e o ES2015 introduziram funções de seta que não fornecem essa ligação por si só (mantém o valor this do contexto lexical anexo).
Método 1: Auto-Self está sendo usado para manter uma referência ao original, mesmo quando o contexto está mudando. É uma técnica frequentemente usada em manipuladores de eventos (especialmente em fechamentos).
Referência : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Método 2 : Função de seta - Uma expressão de função de seta é uma alternativa sintaticamente compacta a uma expressão de função regular,
embora sem suas próprias ligações às palavras-chave this, argumentos, super ou new.target.
As expressões de função de seta são inadequadas como métodos e não podem ser usadas como construtores.
Referência : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Method3 : Bind- O método bind () cria uma nova função que,
quando chamado, tem sua palavra-chave definida com o valor fornecido,
com uma determinada sequência de argumentos que precede qualquer fornecida quando a nova função é chamada.
Referência: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
fonte
Primeiro, você precisa ter uma compreensão clara
scope
e o comportamento dathis
palavra-chave no contexto descope
.this
&scope
:em resumo, o escopo global refere-se ao objeto da janela. Variáveis declaradas em um escopo global são acessíveis de qualquer lugar. Por outro lado, o escopo da função reside dentro de uma função. a variável declarada dentro de uma função não pode ser acessada normalmente fora do mundo.
this
A palavra-chave no escopo global refere-se ao objeto de janela.this
função interna também se refere ao objeto de janela. Portantothis
, sempre se referirá à janela até encontrarmos uma maneira de manipularthis
para indicar um contexto de nossa própria escolha.Maneiras diferentes de manipular
this
funções internas de retorno de chamada:Aqui eu tenho uma função construtora chamada Person. Ele tem uma propriedade chamada
name
e quatro método chamadosayNameVersion1
,sayNameVersion2
,sayNameVersion3
,sayNameVersion4
. Todos os quatro têm uma tarefa específica. Aceite um retorno de chamada e invoque-o. O retorno de chamada possui uma tarefa específica que é registrar a propriedade name de uma instância da função do construtor Person.Agora vamos criar uma instância a partir do construtor de pessoas e chamar diferentes versões do
sayNameVersionX
método (X refere-se a 1,2,3,4)niceCallback
para ver quantas maneiras podemos manipular othis
retorno de chamada interno para se referir àperson
instância.ligar :
O que o bind faz é criar uma nova função com a
this
palavra - chave configurada para o valor fornecido.sayNameVersion1
esayNameVersion2
use bind para manipularthis
a função de retorno de chamada.primeiro, ligue-se
this
ao retorno de chamada dentro do próprio método. E, para o segundo, um retorno de chamada é passado com o objeto vinculado a ele.ligar :
A
first argument
docall
método é usado comothis
dentro da função que é chamado comcall
a ela ligada.sayNameVersion3
usacall
para manipular othis
para se referir ao objeto de pessoa que criamos, em vez do objeto de janela.e é chamado da seguinte maneira:
Aplique :
Semelhante ao
call
, o primeiro argumento deapply
refere-se ao objeto que será indicado pelathis
palavra-chave.sayNameVersion4
usaapply
para manipularthis
para se referir ao objeto de pessoae é chamado da seguinte maneira. Simplesmente o retorno de chamada é passado,
fonte
Não podemos vincular isso
setTimeout()
, como ele sempre executa com o objeto global (Window) , se você deseja acessar othis
contexto na função de retorno de chamada, usandobind()
a função de retorno de chamada que podemos obter como:fonte
A questão gira em torno de como a
this
palavra-chave se comporta em javascript.this
se comporta de maneira diferente como abaixo,this
geralmente é determinado por um contexto de execução de funções.this
refere-se ao objeto global (owindow
objeto).this
seráundefined
como no modo estrito, objeto global se refere aoundefined
lugar dowindow
objeto.call()
,bind()
eapply()
new
palavra-chave é usada (um construtor), isso é vinculado ao novo objeto que está sendo criado.this
- em vez disso,this
são vinculadas lexicamente (ou seja, com base no contexto original)Como a maioria das respostas sugere, podemos usar a função Seta ou
bind()
Método ou Var. Eu citaria um ponto sobre lambdas (função de seta) do Google JavaScript Style GuideO Google recomenda claramente usar lambdas em vez de vincular ou
const self = this
Portanto, a melhor solução seria usar lambdas como abaixo,
Referências:
fonte
this
palavras-chave; é por isso que dividi minha resposta em duas partes, uma sobre athis
segunda sobre o uso de funções / métodos como retornos de chamada. Sinta-se livre para editar a resposta.Atualmente, existe outra abordagem possível se as classes forem usadas no código.
Com o suporte de campos de classe , é possível fazer o seguinte:
Certamente, sob o capô, todas as funções de seta boa e antiga vinculam o contexto, mas, dessa forma, parece muito mais claro que a ligação explícita.
Como é uma proposta do estágio 3, você precisará do babel e do plug - in babel apropriado para processá-lo como agora (08/2018).
fonte
public methodName = (params) => { body }
dentro de uma classe.Outra abordagem, que é a maneira padrão desde a ligação do DOM2
this
no ouvinte de eventos, que permite remover sempre o ouvinte (entre outros benefícios), é ohandleEvent(evt)
método daEventListener
interface:Informações detalhadas sobre o uso
handleEvent
podem ser encontradas aqui: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38fonte
this
em JS:O valor de
this
em JS é 100% determinado pela forma como uma função é chamada, e não como é definida. Nós podemos relativamente fácil encontrar o valor dethis
pelo 'esquerda da regra dot' :this
é o objeto deixado no ponto da função que é chamadothis
dentro de uma função geralmente será o objeto global (global
no nó,window
no navegador). Eu não recomendaria usar athis
palavra - chave aqui porque é menos explícita do que usar algo comowindow
!Function.prototype.bind()
função que pode fixar o valor dethis
. Essas são exceções à regra, mas são realmente úteis para corrigir o valor dethis
.Exemplo no nodeJS
Resultado:
Deixe-me guiá-lo pelas saídas 1 por 1 (ignorando o primeiro log a partir do segundo):
this
éobj2
por causa da esquerda da regra dos pontos, podemos ver comotest1
é chamadoobj2.test1();
.obj2
é deixado do ponto e, portanto, othis
valor.obj2
está à esquerda do ponto,test2
é obrigado aobj1
via dobind()
método. Então othis
valor éobj1
.obj2
está à esquerda do ponto da função que é chamado:obj2.test3()
. Portantoobj2
, será o valor dethis
.obj2.test4()
obj2
fica à esquerda do ponto. No entanto, a função de seta não tem sua própriathis
ligação. Portanto, ele será vinculado aothis
valor do escopo externo, que é omodule.exports
objeto que foi registrado no início.this
usando acall
função Aqui podemos passar othis
valor desejado como argumento, que éobj2
neste caso.fonte