Javascript this
Chamada de Função Simples
Considere a seguinte função:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Observe que estamos executando isso no modo normal, ou seja, o modo estrito não é usado.
Ao executar em um navegador, o valor de this
seria registrado como window
. Isso ocorre porque window
é a variável global no escopo de um navegador da web.
Se você executar esse mesmo pedaço de código em um ambiente como o node.js, this
consulte a variável global no seu aplicativo.
Agora, se executarmos isso no modo estrito adicionando a instrução "use strict";
ao início da declaração da função, this
não se referirá mais à variável global em nenhum dos ambientes. Isso é feito para evitar confusões no modo estrito. this
nesse caso, apenas registraria undefined
, porque é isso que é, não está definido.
Nos seguintes casos, veríamos como manipular o valor de this
.
Chamando uma função em um objeto
Existem diferentes maneiras de fazer isso. Se você tem chamado métodos nativos em Javascript como forEach
e slice
, você já deve saber que a this
variável, nesse caso, refere-se ao Object
em que você chamou essa função (Note-se que em javascript, quase tudo é um Object
, incluindo Array
s e Function
s). Pegue o seguinte código, por exemplo.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
Se um Object
contém uma propriedade que contém a Function
, a propriedade é chamada de método. Este método, quando chamado, sempre terá sua this
variável definida como a Object
qual está associada. Isso vale para os modos estrito e não estrito.
Observe que se um método for armazenado (ou melhor, copiado) em outra variável, a referência a this
não será mais preservada na nova variável. Por exemplo:
// continuing with the previous code snippet
var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
Considerando um cenário mais comumente prático:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
A new
palavra-chave
Considere uma função construtora em Javascript:
function Person (name) {
this.name = name;
this.sayHello = function () {
console.log ("Hello", this);
}
}
var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
Como é que isso funciona? Bem, vamos ver o que acontece quando usamos a new
palavra - chave.
- Chamar a função com a
new
palavra - chave inicializaria imediatamente um Object
tipo Person
.
- O construtor disso
Object
tem seu construtor definido como Person
. Além disso, observe que typeof awal
retornaria Object
apenas.
- A este novo
Object
seria atribuído o protótipo de Person.prototype
. Isso significa que qualquer método ou propriedade no Person
protótipo estaria disponível para todas as instâncias de Person
, inclusive awal
.
- A função em
Person
si agora é invocada; this
sendo uma referência ao objeto recém-construído awal
.
Bem direto, não é?
Observe que a especificação oficial do ECMAScript em nenhum lugar afirma que esses tipos de funções são reais constructor
. São apenas funções normais e new
podem ser usadas em qualquer função. É que nós os usamos como tal e, portanto, os chamamos apenas como tal.
Chamando funções em Funções: call
eapply
Então sim, como function
s também são Objects
(e de fato variáveis de primeira classe em Javascript), até as funções têm métodos que são ... bem, elas próprias.
Todas as funções herdam do global Function
, e dois de seus muitos métodos são call
e apply
, e ambos podem ser usados para manipular o valor da this
função na qual são chamados.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
Este é um exemplo típico de uso call
. Basicamente, pega o primeiro parâmetro e define this
a função foo
como referência thisArg
. Todos os outros parâmetros passados call
são passados para a função foo
como argumentos.
Portanto, o código acima fará logon {myObj: "is cool"}, [1, 2, 3]
no console. Maneira bastante agradável de alterar o valor de this
em qualquer função.
apply
é quase o mesmo que call
aceitar que são necessários apenas dois parâmetros: thisArg
e uma matriz que contém os argumentos a serem passados para a função. Portanto, a call
chamada acima pode ser traduzida para apply
:
foo.apply(thisArg, [1,2,3])
Observe que call
e apply
pode substituir o valor da this
chamada de método definido por ponto que discutimos no segundo marcador. Simples o suficiente :)
Apresentando .... bind
!
bind
é irmão de call
e apply
. É também um método herdado por todas as funções do Function
construtor global em Javascript. A diferença entre bind
e call
/ apply
é que ambos call
e apply
realmente chamarão a função. bind
, por outro lado, retorna uma nova função com thisArg
e arguments
pré-configurada. Vamos dar um exemplo para entender melhor isso:
function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
Veja a diferença entre os três? É sutil, mas eles são usados de maneira diferente. Like call
e apply
, bind
também substituem o valor de this
set pela chamada do método dot.
Observe também que nenhuma dessas três funções altera a função original. call
e apply
retornaria o valor das funções recém-construídas, enquanto bind
retornaria a própria função recém-construída, pronta para ser chamada.
Coisas extras, copie isso
Às vezes, você não gosta do fato de que this
muda com o escopo, especialmente o escopo aninhado. Veja o exemplo a seguir.
var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw \o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup \o/
that.hello(); // "world"
});
}
};
No código acima, vemos que o valor de this
mudou com o escopo aninhado, mas queríamos o valor do this
escopo original. Então nós 'copiado' this
a that
e usou a copiar em vez de this
. Inteligente, não é?
Índice:
- O que é mantido
this
por padrão?
- E se chamarmos a função como um método com a notação Objeto-ponto?
- E se usarmos a
new
palavra - chave?
- Como podemos manipular
this
com call
e apply
?
- Usando
bind
.
- Copiando
this
para resolver problemas de escopo aninhado.