Acabei de encontrar uma situação interessante em JavaScript. Eu tenho uma classe com um método que define vários objetos usando a notação literal de objeto. Dentro desses objetos, o this
ponteiro está sendo usado. Pelo comportamento do programa, deduzi que o this
ponteiro está se referindo à classe na qual o método foi chamado, e não ao objeto que está sendo criado pelo literal.
Isso parece arbitrário, embora seja da maneira que eu esperaria que funcionasse. Esse comportamento é definido? É seguro para vários navegadores? Existe algum raciocínio subjacente ao motivo pelo qual está além da "especificação especificada" (por exemplo, é uma consequência de alguma decisão / filosofia de projeto mais ampla)? Exemplo de código reduzido:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};
Respostas:
Canibalizado de outro post meu, aqui está mais do que você sempre quis saber sobre isso .
Antes de começar, eis a coisa mais importante a ter em mente sobre o Javascript e repetir para si mesmo quando não faz sentido. Javascript não tem classes (ES6
class
é açúcar sintático ). Se algo parece uma classe, é um truque inteligente. Javascript tem objetos e funções . (isso não é 100% preciso, as funções são apenas objetos, mas às vezes pode ser útil pensar nelas como coisas separadas)A variável this está anexada às funções. Sempre que você chama uma função, isso recebe um determinado valor, dependendo de como você chama a função. Isso geralmente é chamado de padrão de chamada.
Existem quatro maneiras de chamar funções em javascript. Você pode chamar a função como um método , como uma função , como um construtor e com apply .
Como método
Um método é uma função anexada a um objeto
Quando invocado como um método, isso será vinculado ao objeto do qual a função / método faz parte. Neste exemplo, isso será associado a foo.
Como uma função
Se você possui uma função autônoma, a variável this será vinculada ao objeto "global", quase sempre o objeto de janela no contexto de um navegador.
Pode ser isso que está atrapalhando você , mas não se sinta mal. Muitas pessoas consideram isso uma má decisão de design. Como um retorno de chamada é chamado como uma função e não como um método, é por isso que você está vendo o que parece ser um comportamento inconsistente.
Muitas pessoas resolvem o problema fazendo algo como, hum, isso
Você define uma variável que aponta para isso . O fechamento (um tópico próprio) mantém isso por aí; portanto, se você chamar a barra como retorno, ainda terá uma referência.
NOTA: No
use strict
modo, se usado como função,this
não está vinculado ao global. (Éundefined
)Como Construtor
Você também pode chamar uma função como construtor. Com base na convenção de nomenclatura que você está usando (TestObject), isso também pode ser o que você está fazendo e é o que está enganando você .
Você invoca uma função como um Construtor com a nova palavra-chave.
Quando chamado como construtor, um novo Objeto será criado, e isso será vinculado a esse objeto. Novamente, se você tiver funções internas e elas forem usadas como retornos de chamada, você as chamará como funções, e isso será vinculado ao objeto global. Use essa var que = esse truque / padrão.
Algumas pessoas pensam que a palavra-chave construtor / nova foi um osso jogado para Java / programadores tradicionais de POO como uma maneira de criar algo semelhante a classes.
Com o método Apply
Por fim, toda função possui um método (sim, funções são objetos em Javascript) chamado "apply". Aplicar permite determinar qual será o valor disso e também transmitir uma matriz de argumentos. Aqui está um exemplo inútil.
fonte
this
seráundefined
para invocações de funções.this
não tem nada a ver com o escopo. Você quer dizer o objeto global .this.confusing = 'hell yeah';
o mesmo quevar confusing = 'hell yeah';
? Então, ambos vão permitirmyObject.confusing
? Seria bom, se não apenas, para que você possa usarthis
para criar as propriedades e outras variáveis para o trabalho interno.function Foo(thought){ this.confusing = thought; }
e entãovar myObject = new Foo("hell yeah");
Chamadas de função
Funções são apenas um tipo de objeto.
Todos os objetos Function têm métodos de chamada e aplicação que executam o objeto Function em que são chamados.
Quando chamado, o primeiro argumento para esses métodos especifica o objeto que será referenciado pela
this
palavra - chave durante a execução da Função - se fornull
ouundefined
, o objeto globalwindow
, for usadothis
.Assim, chamando uma função ...
... entre parênteses -
foo()
- é equivalente afoo.call(undefined)
oufoo.apply(undefined)
, que é efetivamente o mesmo quefoo.call(window)
oufoo.apply(window)
.Argumentos adicionais
call
são passados como argumentos para a chamada de função, enquanto um único argumento adicional paraapply
pode especificar os argumentos para a chamada de função como um objeto semelhante a uma matriz.Assim,
foo(1, 2, 3)
é equivalente afoo.call(null, 1, 2, 3)
oufoo.apply(null, [1, 2, 3])
.Se uma função é uma propriedade de um objeto ...
... acessar uma referência à Função por meio do objeto e chamá-la entre parênteses -
obj.foo()
- é equivalente afoo.call(obj)
oufoo.apply(obj)
.No entanto, funções mantidas como propriedades de objetos não são "vinculadas" a esses objetos. Como você pode ver na definição
obj
acima, como Funções são apenas um tipo de Objeto, elas podem ser referenciadas (e, portanto, podem ser passadas por referência a uma chamada de Função ou retornadas por referência de uma chamada de Função). Quando uma referência a uma função é passado, nenhuma informação adicional sobre onde ele foi passado de é feita com ele, razão pela qual acontece o seguinte:A chamada para nossa referência de função,,
baz
não fornece nenhum contexto para a chamada, portanto é efetivamente o mesmo quebaz.call(undefined)
, portanto,this
acaba fazendo referênciawindow
. Se queremosbaz
saber a que pertenceobj
, precisamos fornecer de alguma forma essas informações quandobaz
são chamadas, e é aí que o primeiro argumento paracall
ouapply
e fechamentos entra em jogo.Cadeias de escopo
Quando uma Função é executada, ela cria um novo escopo e faz referência a qualquer escopo anexo. Quando a função anônima é criada no exemplo acima, ela tem uma referência ao escopo em que foi criada, que é
bind
o escopo. Isso é conhecido como "fechamento".Quando você tenta acessar uma variável, essa "cadeia de escopo" é direcionada para encontrar uma variável com o nome fornecido - se o escopo atual não contiver a variável, você olha para o próximo escopo na cadeia e assim por diante até chegar o escopo global. Quando a função anônima é retornada e
bind
termina a execução, a função anônima ainda tem uma referência aobind
escopo de tal modo quebind
o escopo não "desaparece".Dado todo o exposto, agora você deve entender como o escopo funciona no exemplo a seguir e por que a técnica para passar uma função em torno de "pré-vinculado" com um valor específico
this
dela terá quando for chamada de obras:fonte
Sim. E sim.
O significado de
this
é bastante simples de deduzir:this
for usado dentro de uma função construtora, e a função foi chamada com anew
palavra - chave,this
refere-se ao objeto que será criado.this
continuará a significar o objeto, mesmo em métodos públicos.this
for usado em qualquer outro lugar, incluindo funções protegidas aninhadas , refere-se ao escopo global (que no caso do navegador é o objeto de janela).O segundo caso é obviamente uma falha de design, mas é muito fácil contornar isso usando fechamentos.
fonte
Nesse caso, o interno
this
é vinculado ao objeto global em vez dathis
variável da função externa. É assim que a linguagem é projetada.Veja "JavaScript: The Good Parts", de Douglas Crockford, para uma boa explicação.
fonte
Encontrei um bom tutorial sobre o ECMAScript neste
Qualquer objeto pode ser usado como esse valor do contexto.
Esse recurso é muito importante, porque, ao contrário das variáveis, esse valor nunca participa do processo de resolução do identificador. Ou seja, ao acessar isso em um código, seu valor é obtido diretamente do contexto de execução e sem nenhuma pesquisa na cadeia de escopo. O valor disso é determinado apenas uma vez ao entrar no contexto.
No contexto global, esse valor é o próprio objeto global (ou seja, esse valor aqui é igual ao objeto variável)
No caso de um contexto de função, esse valor em cada chamada de função pode ser diferente
Referência Javascript-the-core e Chapter-3-this
fonte