Como funciona a palavra-chave “this”?
Percebi que não parece haver uma explicação clara do que é a this
palavra-chave e como ela é usada correta (e incorretamente) em JavaScript no site Stack Overflow.
Testemunhei um comportamento muito estranho com ele e não consegui entender por que ocorreu.
Como this
funciona e quando deve ser usado?
Respostas
Recomendo a leitura do artigo Scope in JavaScript ( mirror ) de Mike West primeiro. É uma introdução excelente e amigável aos conceitos e cadeias de escopo em JavaScript.this
Depois que você começar a se acostumar this
, as regras serão bem simples. O padrão ECMAScript 5.1 define this
:
§11.1.1 A
this
palavra-chaveA
this
palavra-chave avalia o valor de ThisBinding do contexto de execução atual
ThisBinding é algo que o interpretador JavaScript mantém enquanto avalia o código JavaScript, como um registro de CPU especial que contém uma referência a um objeto. O interpretador atualiza o ThisBinding sempre que estabelece um contexto de execução em um de apenas três casos diferentes:
1. Contexto de execução global inicial
Este é o caso do código JavaScript que é avaliado no nível superior, por exemplo, quando diretamente dentro de <script>
:
<script>
alert("I'm evaluated in the initial global execution context!");
setTimeout(function () {
alert("I'm NOT evaluated in the initial global execution context.");
}, 1);
</script>
Ao avaliar o código no contexto de execução global inicial, ThisBinding é definido como o objeto global, window
( §10.4.1.1 ).
2. Inserindo o código de avaliação
… Por uma chamada direta para
eval()
ThisBinding é deixado inalterado; é o mesmo valor que ThisBinding do contexto de execução de chamada ( §10.4.2 (2) (a)).… Se não por uma chamada direta para
eval()
ThisBinding é definido para o objeto global como se estivesse executando no contexto de execução global inicial ( §10.4.2 (1)).
§15.1.2.1.1 define o que é uma chamada direta para eval()
. Basicamente, eval(...)
é uma chamada direta, enquanto algo parecido com (0, eval)(...)
ou var indirectEval = eval; indirectEval(...);
é uma chamada indireta para eval()
. Veja a resposta de chuckj para (1, eval) ('this') vs eval ('this') em JavaScript? e o ECMA-262-5 de Dmitry Soshnikov em detalhes. Capítulo 2. Modo estrito. para quando você pode usar uma eval()
chamada indireta .
3. Inserindo o código de função
Isso ocorre ao chamar uma função. Se uma função é chamada em um objeto, como in obj.myMethod()
ou equivalente obj["myMethod"]()
, ThisBinding é definido para o objeto ( obj
no exemplo; §13.2.1 ). Na maioria dos outros casos, ThisBinding é definido como o objeto global ( §10.4.3 ).
O motivo para escrever "na maioria dos outros casos" é porque existem oito funções integradas ECMAScript 5 que permitem que ThisBinding seja especificada na lista de argumentos. Essas funções especiais assumem uma chamada thisArg
que se torna ThisBinding ao chamar a função ( §10.4.3 ).
Essas funções internas especiais são:
Function.prototype.apply( thisArg, argArray )
Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
Array.prototype.every( callbackfn [ , thisArg ] )
Array.prototype.some( callbackfn [ , thisArg ] )
Array.prototype.forEach( callbackfn [ , thisArg ] )
Array.prototype.map( callbackfn [ , thisArg ] )
Array.prototype.filter( callbackfn [ , thisArg ] )
No caso das Function.prototype
funções, elas são chamadas em um objeto de função, mas em vez de definir ThisBinding como o objeto de função, ThisBinding é definido como thisArg
.
No caso das Array.prototype
funções, o dado callbackfn
é chamado em um contexto de execução onde ThisBinding é definido como thisArg
se fornecido; caso contrário, para o objeto global.
Essas são as regras para JavaScript simples. Quando você começa a usar bibliotecas JavaScript (por exemplo, jQuery), você pode descobrir que certas funções de biblioteca manipulam o valor de this
. Os desenvolvedores dessas bibliotecas JavaScript fazem isso porque tende a oferecer suporte aos casos de uso mais comuns e os usuários da biblioteca geralmente consideram esse comportamento mais conveniente. Ao passar funções de retorno de chamada que fazem referência this
a funções de biblioteca, você deve consultar a documentação para obter quaisquer garantias sobre qual é o valor de this
quando a função é chamada.
Se você está se perguntando como uma biblioteca JavaScript manipula o valor de this
, a biblioteca está simplesmente usando uma das funções JavaScript integradas que aceitam a thisArg
. Você também pode escrever sua própria função tomando uma função de retorno de chamada e thisArg
:
function doWork(callbackfn, thisArg) {
//...
if (callbackfn != null) callbackfn.call(thisArg);
}
Há um caso especial que ainda não mencionei. Ao construir um novo objeto por meio do new
operador, o interpretador JavaScript cria um novo objeto vazio, define algumas propriedades internas e, a seguir, chama a função construtora no novo objeto. Assim, quando uma função é chamada em um contexto de construtor, o valor de this
é o novo objeto que o interpretador criou:
function MyType() {
this.someData = "a string";
}
var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);
Funções de seta
As funções de seta (introduzidas no ECMA6) alteram o escopo de this
. Veja a pergunta canônica existente, função de seta vs declaração / expressões de função: são equivalentes / trocáveis? Para maiores informações. Mas resumindo:
As funções de seta não têm sua própria
this
.... vinculação. Em vez disso, esses identificadores são resolvidos no escopo léxico como qualquer outra variável. Isso significa que dentro de uma função de seta,this
... referem-se aos valores dethis
no ambiente em que a função de seta é definida.
Apenas por diversão, teste sua compreensão com alguns exemplos
Para revelar as respostas, passe o mouse sobre as caixas cinza claro.
- Qual é o valor de
this
na linha marcada? Porque?
window
- A linha marcada é avaliada no contexto de execução global inicial.
if (true) {
// What is `this` here?
}
- Qual é o valor de
this
na linha marcada quandoobj.staticFunction()
é executado? Porque?
obj
- Ao chamar uma função em um objeto, ThisBinding é definido para o objeto.
var obj = {
someData: "a string"
};
function myFun() {
return this // What is `this` here?
}
obj.staticFunction = myFun;
console.log("this is window:", obj.staticFunction() == window);
console.log("this is obj:", obj.staticFunction() == obj);
- Qual é o valor de
this
na linha marcada? Porque?
window
Neste exemplo, o interpretador JavaScript insere o código da função, mas como
myFun
/obj.myMethod
não é chamado em um objeto, ThisBinding é definido comowindow
.Isso é diferente do Python, em que acessar um método (
obj.myMethod
) cria um objeto de método vinculado .
var obj = {
myMethod: function () {
return this; // What is `this` here?
}
};
var myFun = obj.myMethod;
console.log("this is window:", myFun() == window);
console.log("this is obj:", myFun() == obj);
- Qual é o valor de
this
na linha marcada? Porque?
window
Este foi complicado. Ao avaliar o código de avaliação,
this
éobj
. No entanto, no código eval,myFun
não é chamado em um objeto, portanto, ThisBinding é definido comowindow
para a chamada.
<!-- no snippet because, seemingly, eval doesn’t work in snippets -->
function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
- Qual é o valor de
this
na linha marcada? Porque?
obj
A linha
myFun.call(obj);
está chamando a função interna especialFunction.prototype.call()
, que aceitathisArg
como o primeiro argumento.
function myFun() {
return this; // What is `this` here?
}
var obj = {
someData: "a string"
};
console.log("this is window:", myFun.call(obj) == window);
console.log("this is obj:", myFun.call(obj) == obj);
A this
palavra-chave se comporta de maneira diferente em JavaScript em comparação com outras linguagens. Em linguagens orientadas a objetos, a this
palavra - chave se refere à instância atual da classe. Em JavaScript, o valor de this
é determinado pelo contexto de invocação de function ( context.function()
) e onde é chamado.
1. Quando usado em contexto global
Quando você usa this
no contexto global, é vinculado ao objeto global ( window
no navegador)
document.write(this); //[object Window]
Quando você usa this
dentro de uma função definida no contexto global, this
ainda está vinculado ao objeto global, pois a função é na verdade um método de contexto global.
function f1()
{
return this;
}
document.write(f1()); //[object Window]
Acima f1
é feito um método de objeto global. Assim, também podemos chamá-lo no window
objeto da seguinte maneira:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. Quando usado dentro do método do objeto
Quando você usa uma this
palavra-chave dentro de um método de objeto, this
é vinculado ao objeto envolvente "imediato".
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
Acima, coloquei a palavra imediato entre aspas duplas. É para deixar claro que, se você aninhar o objeto dentro de outro objeto, this
estará vinculado ao pai imediato.
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
Mesmo se você adicionar função explicitamente ao objeto como um método, ainda segue as regras acima, que this
ainda aponta para o objeto pai imediato.
var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
3. Ao invocar a função sem contexto
Quando você usa uma this
função interna que é chamada sem qualquer contexto (ou seja, não em qualquer objeto), ela é vinculada ao objeto global ( window
no navegador) (mesmo se a função for definida dentro do objeto).
var context = "global";
var obj = {
context: "object",
method: function () {
function f() {
var context = "function";
return this + ":" +this.context;
};
return f(); //invoked without context
}
};
document.write(obj.method()); //[object Window]:global
Experimentando tudo com funções
Podemos tentar os pontos acima com funções também. No entanto, existem algumas diferenças.
- Acima, adicionamos membros a objetos usando notação literal de objeto. Podemos adicionar membros às funções usando
this
. para especificá-los. - A notação literal de objeto cria uma instância de objeto que podemos usar imediatamente. Com a função, podemos primeiro precisar criar sua instância usando o
new
operador. - Também em uma abordagem literal de objeto, podemos adicionar explicitamente membros a um objeto já definido usando o operador ponto. Isso é adicionado apenas à instância específica. No entanto, adicionei a variável ao protótipo da função para que ela seja refletida em todas as instâncias da função.
A seguir, experimentei todas as coisas que fizemos com Object e this
acima, mas primeiro criando uma função em vez de escrever um objeto diretamente.
/*********************************************************************
1. When you add variable to the function using this keyword, it
gets added to the function prototype, thus allowing all function
instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
this.name = "ObjDefinition";
this.getName = function(){
return this+":"+this.name;
}
}
obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition
/*********************************************************************
2. Members explicitly added to the function protorype also behave
as above: all function instances have their own copy of the
variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
return "v"+this.version; //see how this.version refers to the
//version variable added through
//prototype
}
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
3. Illustrating that the function variables added by both above
ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
4. `this` keyword refers to the immediate parent object. If you
nest the object through function prototype, then `this` inside
object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
getName1 : function(){
return this+":"+this.name;
}
};
document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj
/*********************************************************************
5. If the method is on an object's prototype chain, `this` refers
to the object the method was called on, as if the method was on
the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
//as its prototype
obj3.a = 999; //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
//calling obj3.fun() makes
//ProtoObj.fun() to access obj3.a as
//if fun() is defined on obj3
4. Quando usado dentro da função de construtor .
Quando a função é usada como um construtor (ou seja, quando é chamada com a new
palavra - chave), o this
corpo da função dentro aponta para o novo objeto que está sendo construído.
var myname = "global context";
function SimpleFun()
{
this.myname = "simple function";
}
var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
// object being constructed thus adding any member
// created inside SimipleFun() using this.membername to the
// object being constructed
//2. And by default `new` makes function to return newly
// constructed object if no explicit return value is specified
document.write(obj1.myname); //simple function
5. Quando usado dentro da função definida na cadeia de protótipo
Se o método está na cadeia de protótipos de um objeto, this
dentro desse método se refere ao objeto em que o método foi chamado, como se o método estivesse definido no objeto.
var ProtoObj = {
fun: function () {
return this.a;
}
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun()
//to be the method on its prototype chain
var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999
//Notice that fun() is defined on obj3's prototype but
//`this.a` inside fun() retrieves obj3.a
6. Dentro das funções call (), apply () e bind ()
- Todos esses métodos são definidos em
Function.prototype
. - Esses métodos permitem escrever uma função uma vez e invocá-la em um contexto diferente. Ou seja, permitem especificar o valor
this
que será utilizado durante a execução da função. Eles também aceitam quaisquer parâmetros a serem passados para a função original quando ela é chamada. fun.apply(obj1 [, argsArray])
Defineobj1
como o valor dethis
dentrofun()
e chama osfun()
elementos de passagem deargsArray
como seus argumentos.fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Defineobj1
como o valor dethis
dentrofun()
e chamafun()
passandoarg1, arg2, arg3, ...
como seus argumentos.fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Retorna a referência à funçãofun
comthis
dentro do limite de diversãoobj1
e parâmetros defun
limite para os parâmetros especificadosarg1, arg2, arg3,...
.- Até agora a diferença entre
apply
,call
ebind
deve ter se tornado aparente.apply
permite especificar os argumentos para funcionar como um objeto tipo array, ou seja, um objeto com umalength
propriedade numérica e propriedades inteiras não negativas correspondentes. Considerando quecall
permite especificar os argumentos para a função diretamente. Ambosapply
ecall
imediatamente chama a função no contexto especificado e com os argumentos especificados. Por outro lado,bind
simplesmente retorna a função associada aothis
valor especificado e aos argumentos. Podemos capturar a referência a esta função retornada atribuindo-a a uma variável e, posteriormente, podemos chamá-la a qualquer momento.
function add(inc1, inc2)
{
return this.a + inc1 + inc2;
}
var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
//above add.call(o,5,6) sets `this` inside
//add() to `o` and calls add() resulting:
// this.a + inc1 + inc2 =
// `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
// `o.a` i.e. 4 + 5 + 6 = 15
var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />"); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
// 4 + 5 + 6 = 15
document.write(h() + "<br />"); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN</code>
7. this
manipuladores de eventos internos
- Quando você atribui função diretamente a manipuladores de eventos de um elemento, o uso de
this
função de manipulação de eventos diretamente dentro se refere ao elemento correspondente. Essa atribuição direta de função pode ser feita usando oaddeventListener
método ou por meio dos métodos tradicionais de registro de eventos, comoonclick
. - Da mesma forma, quando você usa
this
diretamente dentro da propriedade do evento (como<button onclick="...this..." >
) do elemento, ela se refere ao elemento. - No entanto, o uso de
this
indiretamente por meio de outra função chamada dentro da função de tratamento de eventos ou propriedade de evento resolve para o objeto globalwindow
. - O mesmo comportamento acima é obtido quando anexamos a função ao manipulador de eventos usando o método de modelo de Registro de Eventos da Microsoft
attachEvent
. Em vez de atribuir a função ao manipulador de eventos (e assim tornar o método de função do elemento), ele chama a função no evento (efetivamente chamando-a no contexto global).
Eu recomendo tentar isso melhor no JSFiddle .
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
8. this
na função de seta ES6
Em uma função de seta, this
se comportará como variáveis comuns: será herdado de seu escopo léxico. A função this
, onde a função de seta é definida, será a função de seta this
.
Então, esse é o mesmo comportamento que:
(function(){}).bind(this)
Veja o seguinte código:
const globalArrowFunction = () => {
return this;
};
console.log(globalArrowFunction()); //window
const contextObject = {
method1: () => {return this},
method2: function(){
return () => {return this};
}
};
console.log(contextObject.method1()); //window
const contextLessFunction = contextObject.method1;
console.log(contextLessFunction()); //window
console.log(contextObject.method2()()) //contextObject
const innerArrowFunction = contextObject.method2();
console.log(innerArrowFunction()); //contextObject
Javascript's this
Invocação 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 trecho de código em um ambiente como node.js, fará this
referência à variável global em 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 faremos mais referência à variável global em nenhum dos ambientes. Isso é feito para evitar confusões no modo estrito. this
seria, neste caso, apenas log undefined
, porque é isso que é, não está definido.
Nos casos a seguir, veríamos como manipular o valor de this
.
Chamar uma função em um objeto
Existem diferentes maneiras de fazer isso. Se você chamou métodos nativos em Javascript como forEach
e slice
, você já deve saber que a this
variável nesse caso se refere ao Object
no qual você chamou essa função (observe que em javascript, quase tudo é um Object
, incluindo Array
s e Function
s). Veja o código a seguir, 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 um Function
, a propriedade é chamada de método. Este método, quando chamado, sempre terá sua this
variável configurada para o Object
qual está associado. Isso é verdadeiro 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 umObject
tipoPerson
. - O construtor deste
Object
tem seu construtor definido comoPerson
. Além disso, observe quetypeof awal
retornariaObject
apenas. - Este novo
Object
seria atribuído ao protótipo dePerson.prototype
. Isso significa que qualquer método ou propriedade noPerson
protótipo estaria disponível para todas as instâncias dePerson
, incluindoawal
. - A função em
Person
si agora é chamada;this
sendo uma referência ao objeto recém-construídoawal
.
Muito simples, hein?
Observe que a especificação oficial do ECMAScript em nenhum lugar afirma que esses tipos de funções são constructor
funções reais . Eles são apenas funções normais e new
podem ser usados em qualquer função. Acontece que os usamos como tal, e por isso os chamamos apenas como tal.
Chamando funções em Funções: call
eapply
Então sim, uma vez que function
s também são Objects
(e de fato variáveis de primeira classe em Javascript), até mesmo funções têm métodos que são ... bem, funções em si.
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 de this
na 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, ele pega o primeiro parâmetro e define this
a função foo
como uma referência para thisArg
. Todos os outros parâmetros passados para call
são passados para a função foo
como argumentos.
Portanto, o código acima será registrado {myObj: "is cool"}, [1, 2, 3]
no console. Uma maneira muito boa de alterar o valor de this
qualquer função.
apply
é quase o mesmo que call
aceitar que leva apenas dois parâmetros: thisArg
e um array que contém os argumentos a serem passados para a função. Portanto, a call
chamada acima pode ser traduzida apply
assim:
foo.apply(thisArg, [1,2,3])
Observe que call
e apply
pode substituir o valor da this
invocação do método set by dot que discutimos no segundo item. 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 invocarão a função. bind
, por outro lado, retorna uma nova função com o thisArg
e arguments
predefinido. 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 forma diferente. Like call
e apply
, bind
também substituirá o valor de this
definido pela invocação do método de ponto.
Observe também que nenhuma dessas três funções altera a função original. call
e apply
retornaria o valor de 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 isto
Às vezes, você não gosta do fato de que this
muda com o escopo, especialmente o escopo aninhado. Dê uma olhada no 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 de this
do escopo original. Então nós 'copiado' this
a that
e usou a copiar em vez de this
. Inteligente, hein?
Índice:
- O que é retido
this
por padrão? - E se chamarmos a função como um método com notação de objeto-ponto?
- E se usarmos a
new
palavra - chave? - Como podemos manipular
this
comcall
eapply
? - Usando
bind
. - Copiar
this
para resolver problemas de escopo aninhado.
"isso" tem tudo a ver com escopo. Cada função tem seu próprio escopo e, como tudo em JS é um objeto, até mesmo uma função pode armazenar alguns valores em si mesma usando "this". OOP 101 ensina que "isto" só se aplica a instâncias de um objeto. Portanto, toda vez que uma função é executada, uma nova "instância" dessa função tem um novo significado de "isso".
A maioria das pessoas fica confusa quando tenta usar "this" dentro de funções de fechamento anônimas como:
(função (valor) { this.value = value; $ ('. some-elements'). each (function (elt) { elt.innerHTML = this.value; // uh oh !! possivelmente indefinido }); }) (2);
Então aqui, dentro de cada (), "isto" não contém o "valor" que você espera que (de
this.value = value;acima dele). Então, para superar esse problema (sem trocadilhos), um desenvolvedor pode:
(função (valor) { var self = this; // pequena mudança self.value = value; $ ('. some-elements'). each (function (elt) { elt.innerHTML = self.value; // ufa !! == 2 }); }) (2);
Experimente; você começará a gostar deste padrão de programação
Desde que este tópico aumentou, eu compilei alguns pontos para leitores novos no this
tópico.
Como é o valor de this
determinado?
Usamos essa semelhante à maneira como usamos pronomes nas línguas naturais como o Inglês: “John está correndo rápido, porque ele está tentando pegar o trem.” Em vez disso, poderíamos ter escrito “… John está tentando pegar o trem”.
var person = {
firstName: "Penelope",
lastName: "Barrymore",
fullName: function () {
// We use "this" just as in the sentence above:
console.log(this.firstName + " " + this.lastName);
// We could have also written:
console.log(person.firstName + " " + person.lastName);
}
}
this
não recebe um valor até que um objeto invoque a função onde está definido. No escopo global, todas as variáveis e funções globais são definidas no window
objeto. Portanto, this
em uma função global se refere a (e tem o valor de) o window
objeto global .
Quando use strict
, this
em funções globais e anônimas que não estão vinculadas a nenhum objeto, possui um valor de undefined
.
A this
palavra-chave é mais mal compreendida quando: 1) pegamos emprestado um método que usa this
, 2) atribuímos um método que usa this
para uma variável, 3) uma função que usa this
é passada como uma função de retorno de chamada e 4) this
é usada dentro de uma closure - uma função interna. (2)
O que guarda o futuro
Definido no ECMA Script 6 , as funções de seta adotam a this
vinculação do escopo delimitador (função ou global).
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically inherited from `foo()`
console.log(this.a);
};
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };
var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!
Embora as funções de seta forneçam uma alternativa ao uso bind()
, é importante observar que elas essencialmente desativam o this
mecanismo tradicional em favor de um escopo léxico mais amplamente compreendido. (1)
Referências:
- this & Object Prototypes , de Kyle Simpson. © 2014 Getify Solutions.
- javascriptissexy.com - http://goo.gl/pvl0GX
- Angus Croll - http://goo.gl/Z2RacU
this
em JavaScript sempre se refere ao 'dono' da função que está sendo executada .
Se nenhum proprietário explícito for definido, o principal proprietário, o objeto janela, será referenciado.
Então se eu fizesse
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
faria referência ao objeto do elemento. Mas tenha cuidado, muitas pessoas cometem esse erro.
<element onclick="someKindOfFunction()">
No último caso, você meramente faz referência à função, não a entrega ao elemento. Portanto, this
fará referência ao objeto janela.
Cada contexto de execução em javascript tem um este parâmetro que é definido por:
- Como a função é chamada (incluindo como um método de objeto, uso de call e apply , uso de new )
- Uso de ligação
- Lexicamente para funções de seta (elas adotam o this de seu contexto de execução externo)
- Se o código está em modo estrito ou não estrito
- Se o código foi invocado usando eval
Você pode definir o valor dessa usando func.call
, func.apply
ou func.bind
.
Por padrão, e o que confunde a maioria dos iniciantes, quando um ouvinte é chamado depois que um evento é gerado em um elemento DOM, o valor this da função é o elemento DOM.
jQuery torna isso trivial para alterar com jQuery.proxy.
Daniel, explicação incrível! Algumas palavras sobre esta e uma boa lista de this
ponteiros de contexto de execução no caso de manipuladores de eventos.
Em duas palavras, this
em JavaScript aponta o objeto de quem (ou de cujo contexto de execução) a função atual foi executada e é sempre somente leitura, você não pode defini-la de qualquer maneira (tal tentativa terminará com 'Canhoto inválido lado na mensagem da atribuição.
Para manipuladores de eventos: os manipuladores de eventos embutidos, como <element onclick="foo">
, sobrescrevem quaisquer outros manipuladores anexados antes e antes, portanto, tome cuidado e é melhor ficar longe da delegação de eventos embutidos. E obrigado a Zara Alaverdyan que me inspirou a esta lista de exemplos através de um debate dissidente :)
el.onclick = foo; // in the foo - obj
el.onclick = function () {this.style.color = '#fff';} // obj
el.onclick = function() {doSomething();} // In the doSomething - Window
el.addEventListener('click',foo,false) // in the foo - obj
el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
<button onclick="this.style.color = '#fff';"> // obj
<button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">
Aqui é uma fonte boa de this
no JavaScript
.
Aqui está o resumo:
global isso
Em um navegador, no escopo global,
this
está owindow
objeto<script type="text/javascript"> console.log(this === window); // true var foo = "bar"; console.log(this.foo); // "bar" console.log(window.foo); // "bar"
Ao
node
usar o repl,this
é o principal namespace. Você pode se referir a ele comoglobal
.>this { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... >global === this true
Ao
node
executar a partir de um script,this
no escopo global começa como um objeto vazio. Não é o mesmo queglobal
\\test.js console.log(this); \\ {} console.log(this === global); \\ fasle
funcionar isso
Exceto no caso de manipuladores de eventos DOM ou quando um thisArg
é fornecido (veja mais abaixo), tanto no nó quanto em um navegador usando this
uma função que não é chamada com new
referências ao escopo global ...
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
Se você usar use strict;
, nesse caso this
seráundefined
<script type="text/javascript">
foo = "bar";
function testThis() {
"use strict";
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined
</script>
Se você chamar uma função com new
o this
será um novo contexto, não fará referência ao mundial this
.
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
new testThis();
console.log(this.foo); //logs "bar"
console.log(new testThis().foo); //logs "foo"
</script>
- prototipar isso
As funções que você cria tornam-se objetos de função. Eles obtêm automaticamente uma prototype
propriedade especial , à qual você pode atribuir valores. Ao criar uma instância chamando sua função, new
você obtém acesso aos valores atribuídos à prototype
propriedade. Você acessa esses valores usando this
.
function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
Geralmente é um erro atribuir matrizes ou objetos no prototype
. Se você quiser que as instâncias tenham seus próprios arrays, crie-os na função, não no protótipo.
function Thing() {
this.things = [];
}
var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
- objete isso
Você pode usar this
em qualquer função de um objeto para se referir a outras propriedades desse objeto. Isso não é o mesmo que uma instância criada com new
.
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
- Evento DOM este
Em um manipulador de eventos HTML DOM, this
é sempre uma referência ao elemento DOM ao qual o evento foi anexado
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
}
var listener = new Listener();
document.getElementById("foo").click();
A menos que você tenha bind
o contexto
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs Listener {handleClick: function}
}
var listener = new Listener();
document.getElementById("foo").click();
- HTML isto
Dentro dos atributos HTML nos quais você pode colocar JavaScript, this
está uma referência ao elemento.
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
- avaliar isso
Você pode usar eval
para acessar this
.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
- com isso
Você pode usar with
para adicionar this
ao escopo atual para ler e gravar valores this
sem se referir this
explicitamente.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
with (this) {
console.log(foo);
foo = "foo";
}
}
var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
- jQuery isso
o jQuery, em muitos lugares, fará this
referência a um elemento DOM.
<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () { console.log(this); //logs <div class="foo... }); $(".foo").on("click", function () {
console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
this.click();
});
</script>
Há muita confusão sobre como "esta" palavra-chave é interpretada em JavaScript. Esperançosamente, este artigo fará com que todos descansem de uma vez por todas. E muito mais. Por favor, leia todo o artigo com atenção. Esteja avisado de que este artigo é longo.
Independentemente do contexto em que é usado, "this" sempre faz referência ao "objeto atual" em Javascript. No entanto, o que é o "objeto atual" difere de acordo com o contexto . O contexto pode ser exatamente 1 dos 6 a seguir:
- Global (ou seja, fora de todas as funções)
- Chamada interna direta de "Função não vinculada" (ou seja, uma função que não foi vinculada chamando functionName.bind )
- Chamada interna indireta de "função não vinculada" por meio de functionName.call e functionName.apply
- Dentro da chamada de "Função vinculada" (ou seja, uma função que foi vinculada chamando functionName.bind )
- Enquanto Criação de Objetos por meio de "novo"
- Manipulador de eventos DOM Inline interno
O seguinte descreve cada um desses contextos, um por um:
Global Context (i.e. Outside all functions):
Outside all functions (i.e. in global context) the "current object" (and hence the value of "this") is always the "window" object for browsers.
Inside Direct "Non Bound Function" Call:
Inside a Direct "Non Bound Function" Call, the object that invoked the function call becomes the "current object" (and hence the value of "this"). If a function is called without a explicit current object, the current object is either the "window" object (For Non Strict Mode) or undefined (For Strict Mode) . Any function (or variable) defined in Global Context automatically becomes a property of the "window" object.For e.g Suppose function is defined in Global Context as
function UserDefinedFunction(){ alert(this) }
it becomes the property of the window object, as if you have defined it as
window.UserDefinedFunction=function(){ alert(this) }
In "Non Strict Mode", Calling/Invoking this function directly through "UserDefinedFunction()" will automatically call/invoke it as "window.UserDefinedFunction()" making "window" as the "current object" (and hence the value of "this") within "UserDefinedFunction".Invoking this function in "Non Strict Mode" will result in the following
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
In "Strict Mode", Calling/Invoking the function directly through "UserDefinedFunction()" will "NOT" automatically call/invoke it as "window.UserDefinedFunction()".Hence the "current object" (and the value of "this") within "UserDefinedFunction" shall be undefined. Invoking this function in "Strict Mode" will result in the following
UserDefinedFunction() // displays undefined
However, invoking it explicitly using window object shall result in the following
window.UserDefinedFunction() // "always displays [object Window] irrespective of mode."
Let us look at another example. Please look at the following code
function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } o1.f() // Shall display 1,2,undefined,undefined o2.f() // Shall display undefined,undefined,3,4
In the above example we see that when "UserDefinedFunction" was invoked through o1, "this" takes value of o1 and the value of its properties "a" and "b" get displayed. The value of "c" and "d" were shown as undefined as o1 does not define these properties
Similarly when "UserDefinedFunction" was invoked through o2, "this" takes value of o2 and the value of its properties "c" and "d" get displayed.The value of "a" and "b" were shown as undefined as o2 does not define these properties.
Inside Indirect "Non Bound Function" Call through functionName.call and functionName.apply:
When a "Non Bound Function" is called through functionName.call or functionName.apply, the "current object" (and hence the value of "this") is set to the value of "this" parameter (first parameter) passed to call/apply. The following code demonstrates the same.
function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4 UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4 o1.f.call(o2) // Shall display undefined,undefined,3,4 o1.f.apply(o2) // Shall display undefined,undefined,3,4 o2.f.call(o1) // Shall display 1,2,undefined,undefined o2.f.apply(o1) // Shall display 1,2,undefined,undefined
The above code clearly shows that the "this" value for any "NON Bound Function" can be altered through call/apply. Also,if the "this" parameter is not explicitly passed to call/apply, "current object" (and hence the value of "this") is set to "window" in Non strict mode and "undefined" in strict mode.
Inside "Bound Function" Call (i.e. a function that has been bound by calling functionName.bind):
A bound function is a function whose "this" value has been fixed. The following code demonstrated how "this" works in case of bound function
function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction, bf:null } var o2={ c:3, d:4, f:UserDefinedFunction, bf:null } var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1 bound1() // Shall display 1,2,undefined,undefined var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2 bound2() // Shall display undefined,undefined,3,4 var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2 bound3() // Shall display undefined,undefined,3,4 var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1 bound4() // Shall display 1,2,undefined,undefined o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2 o1.bf() // Shall display undefined,undefined,3,4 o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1 o2.bf() // Shall display 1,2,undefined,undefined bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
As given in the code above, "this" value for any "Bound Function" CANNOT be altered through call/apply. Also, if the "this" parameter is not explicitly passed to bind, "current object" (and hence the value of "this" ) is set to "window" in Non strict mode and "undefined" in strict mode. One more thing. Binding an already bound function does not change the value of "this". It remains set as the value set by first bind function.
While Object Creation through "new":
Inside a constructor function, the "current object" (and hence the value of "this") references the object that is currently being created through "new" irrespective of the bind status of the function. However if the constructor is a bound function it shall get called with predefined set of arguments as set for the bound function.
Inside Inline DOM event handler:
Please look at the following HTML Snippet
<button onclick='this.style.color=white'>Hello World</button> <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
The "this" in above examples refer to "button" element and the "div" element respectively.
In the first example, the font color of the button shall be set to white when it is clicked.
In the second example when the "div" element is clicked it shall call the OnDivClick function with its second parameter referencing the clicked div element. However the value of "this" within OnDivClick SHALL NOT reference the clicked div element. It shall be set as the "window object" or "undefined" in Non strict and Strict Modes respectively (if OnDivClick is an unbound function) or set to a predefined Bound value (if OnDivClick is a bound function)
The following summarizes the entire article
In Global Context "this" always refers to the "window" object
Whenever a function is invoked, it is invoked in context of an object ("current object"). If the current object is not explicitly provided, the current object is the "window object" in NON Strict Mode and "undefined" in Strict Mode by default.
The value of "this" within a Non Bound function is the reference to object in context of which the function is invoked ("current object")
The value of "this" within a Non Bound function can be overriden by call and apply methods of the function.
The value of "this" is fixed for a Bound function and cannot be overriden by call and apply methods of the function.
Binding and already bound function does not change the value of "this". It remains set as the value set by first bind function.
The value of "this" within a constructor is the object that is being created and initialized
The value of "this" within an inline DOM event handler is reference to the element for which the event handler is given.
Probably the most detailed and comprehensive article on this
is the following:
Gentle explanation of 'this' keyword in JavaScript
The idea behind this
is to understand that the function invocation types have the significant importance on setting this
value.
When having troubles identifying this
, do not ask yourself:
Where is
this
taken from?
but do ask yourself:
How is the function invoked?
For an arrow function (special case of context transparency) ask yourself:
What value has
this
where the arrow function is defined?
This mindset is correct when dealing with this
and will save you from headache.
This is the best explanation I've seen: Understand JavaScripts this with Clarity
The this reference ALWAYS refers to (and holds the value of) an object—a singular object—and it is usually used inside a function or a method, although it can be used outside a function in the global scope. Note that when we use strict mode, this holds the value of undefined in global functions and in anonymous functions that are not bound to any object.
There are Four Scenarios where this can be confusing:
- When we pass a method (that uses this) as an argument to be used as a callback function.
- When we use an inner function (a closure). It is important to take note that closures cannot access the outer function’s this variable by using the this keyword because the this variable is accessible only by the function itself, not by inner functions.
- When a method which relies on this is assigned to a variable across contexts, in which case this references another object than originally intended.
- When using this along with the bind, apply, and call methods.
He gives code examples, explanations, and solutions, which I thought was very helpful.
this
is one of the misunderstood concept in JavaScript because it behaves little differently from place to place. Simply, this
refers to the "owner" of the function we are currently executing.
this
helps to get the current object (a.k.a. execution context) we work with. If you understand in which object the current function is getting executed, you can understand easily what current this
is
var val = "window.val"
var obj = {
val: "obj.val",
innerMethod: function () {
var val = "obj.val.inner",
func = function () {
var self = this;
return self.val;
};
return func;
},
outerMethod: function(){
return this.val;
}
};
//This actually gets executed inside window object
console.log(obj.innerMethod()()); //returns window.val
//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val
console.log(obj.outerMethod()); //returns obj.val
Above we create 3 variables with same name 'val'. One in global context, one inside obj and the other inside innerMethod of obj. JavaScript resolves identifiers within a particular context by going up the scope chain from local go global.
Few places where this
can be differentiated
Calling a method of a object
var status = 1;
var helper = {
status : 2,
getStatus: function () {
return this.status;
}
};
var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2
var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1
When line1 is executed, JavaScript establishes an execution context (EC) for the function call, setting this
to the object referenced by whatever came before the last ".". so in the last line you can understand that a()
was executed in the global context which is the window
.
With Constructor
this
can be used to refer to the object being created
function Person(name){
this.personName = name;
this.sayHello = function(){
return "Hello " + this.personName;
}
}
var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott
var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined
When new Person()
is executed, a completely new object is created. Person
is called and its this
is set to reference that new object.
Function call
function testFunc() {
this.name = "Name";
this.myCustomAttribute = "Custom Attribute";
return this;
}
var whatIsThis = testFunc();
console.log(whatIsThis); //window
var whatIsThis2 = new testFunc();
console.log(whatIsThis2); //testFunc() / object
console.log(window.myCustomAttribute); //Custom Attribute
If we miss new
keyword, whatIsThis
referes to the most global context it can find(window
)
With event handlers
If the event handler is inline, this
refers to global object
<script type="application/javascript">
function click_handler() {
alert(this); // alerts the window object
}
</script>
<button id='thebutton' onclick='click_handler()'>Click me!</button>
When adding event handler through JavaScript, this
refers to DOM element that generated the event.
- You can also manipulate the context using
.apply()
.call()
and.bind()
- JQuery proxy is another way you can use to make sure this in a function will be the value you desire. (Check Understanding $.proxy(), jQuery.proxy() usage)
- What does var that = this means in JavaScript
In pseudoclassical terms, the way many lectures teach the 'this' keyword is as an object instantiated by a class or object constructor. Each time a new object is constructed from a class, imagine that under the hood a local instance of a 'this' object is created and returned. I remember it taught like this:
function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}
var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
The value of "this" depends on the "context" in which the function is executed. The context can be any object or the global object, i.e., window.
So the Semantic of "this" is different from the traditional OOP languages. And it causes problems: 1. when a function is passed to another variable (most likely, a callback); and 2. when a closure is invoked from a member method of a class.
In both cases, this is set to window.
Whould this help? (Most confusion of 'this' in javascript is coming from the fact that it generally is not linked to your object, but to the current executing scope -- that might not be exactly how it works but is always feels like that to me -- see the article for a complete explanation)
A little bit info about this keyword
Let's log this
keyword to the console in global scope without any more code but
console.log(this)
In Client/Browser this
keyword is a global object which is window
console.log(this === window) // true
and
In Server/Node/Javascript runtime this
keyword is also a global object which is module.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
Keep in mind exports
is just a reference to module.exports
this use for Scope just like this
<script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{ var txt=''; txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>
value of txt1 and txt is same in Above example $(this)=$('#tbleName tbody tr') is Same
I have a different take on this
from the other answers that I hope is helpful.
One way to look at JavaScript is to see that there are only 1 way to call a function1. It is
functionObject.call(objectForThis, arg0, arg1, arg2, ...);
There is always some value supplied for objectForThis
.
Everything else is syntactic sugar for functionObject.call
So, everything else can be described by how it translates into functionObject.call
.
If you just call a function then this
is the "global object" which in the browser is the window
function foo() {
console.log(this);
}
foo(); // this is the window object
In other words,
foo();
was effectively translated into
foo.call(window);
Note that if you use strict mode then this
will be undefined
'use strict';
function foo() {
console.log(this);
}
foo(); // this is the window object
which means
In other words,
foo();
was effectively translated into
foo.call(undefined);
In JavaScript there are operators like +
and -
and *
. There is also the dot operator which is .
The .
operator when used with a function on the right and an object on the left effectively means "pass object as this
to function.
Example
const bar = {
name: 'bar',
foo() {
console.log(this);
},
};
bar.foo(); // this is bar
In other words bar.foo()
translates into const temp = bar.foo; temp.call(bar);
Note that it doesn't matter how the function was created (mostly...). All of these will produce the same results
const bar = {
name: 'bar',
fn1() { console.log(this); },
fn2: function() { console.log(this); },
fn3: otherFunction,
};
function otherFunction() { console.log(this) };
bar.fn1(); // this is bar
bar.fn2(); // this is bar
bar.fn3(); // this is bar
Again these all are just syntactic sugar for
{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }
One other wrinkle is the prototype chain. When you use a.b
JavaScript first looks on the object referenced directly by a
for the property b
. If b
is not found on the object then JavaScript will look in the object's prototype to find b
.
There are various ways to define an object's prototype, the most common in 2019 is the class
keyword. For the purposes of this
though it doesn't matter. What matters is that as it looks in object a
for property b
if it finds property b
on the object or in it's prototype chain if b
ends up being a function then the same rules as above apply. The function b
references will be called using the call
method and passing a
as objectForThis as shown a the top of this answer.
Now. Let's imagine we make a function that explicitly sets this
before calling another function and then call it with the .
(dot) operator
function foo() {
console.log(this);
}
function bar() {
const objectForThis = {name: 'moo'}
foo.call(objectForThis); // explicitly passing objectForThis
}
const obj = {
bar,
};
obj.bar();
Following the translation to use call
, obj.bar()
becomes const temp = obj.bar; temp.call(obj);
. When we enter the bar
function we call foo
but we explicitly passed in another object for objectForThis so when we arrive at foo this
is that inner object.
This is what both bind
and =>
functions effectively do. They are more syntactic sugar. They effectively build a new invisible function exactly like bar
above that explicitly sets this
before it calls whatever function is specified. In the case of bind this
is set to whatever you pass to bind
.
function foo() {
console.log(this);
}
const bar = foo.bind({name: 'moo'});
// bind created a new invisible function that calls foo with the bound object.
bar();
// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above
bar.call({name: 'other'});
Note that if functionObject.bind
did not exist we could make our own like this
function bind(fn, objectForThis) {
return function(...args) {
return fn.call(objectForthis, ...args);
};
}
and then we could call it like this
function foo() {
console.log(this);
}
const bar = bind(foo, {name:'abc'});
Arrow functions, the =>
operator are syntactic sugar for bind
const a = () => {console.log(this)};
is the same as
const tempFn = function() {console.log(this)};
const a = tempFn.bind(this);
Just like bind
, a new invisible function is created that calls the given function with a bound value for objectForThis
but unlike bind
the object to be bound is implicit. It's whatever this
happens to be when the =>
operator is used.
So, just like the rules above
const a = () => { console.log(this); } // this is the global object
'use strict';
const a = () => { console.log(this); } // this is undefined
function foo() {
return () => { console.log(this); }
}
const obj = {
foo,
};
const b = obj.foo();
b();
obj.foo()
translates to const temp = obj.foo; temp.call(obj);
which means the arrow operator inside foo
will bind obj
to a new invisible function and return that new invisible function which is assigned to b
. b()
will work as it always has as b.call(window)
or b.call(undefined)
calling the new invisible function that foo
created. That invisible function ignores the this
passed into it and passes obj
as objectForThis` to the arrow function.
The code above translates to
function foo() {
function tempFn() {
console.log(this);
}
return tempFn.bind(this);
}
const obj = {
foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);
1apply
is another function similar to call
functionName.apply(objectForThis, arrayOfArgs);
But as of ES6 conceptually you can even translate that into
functionName.call(objectForThis, ...arrayOfArgs);
Summary this
Javascript:
- The value of
this
is determined by how the function is invoked not, where it was created! - Usually the value of
this
is determined by the Object which is left of the dot. (window
in global space) - In event listeners the value of
this
refers to the DOM element on which the event was called. - When in function is called with the
new
keyword the value ofthis
refers to the newly created object - You can manipulate the value of
this
with the functions:call
,apply
,bind
Example:
let object = {
prop1: function () {console.log(this);}
}
object.prop1(); // object is left of the dot, thus this is object
const myFunction = object.prop1 // We store the function in the variable myFunction
myFunction(); // Here we are in the global space
// myFunction is a property on the global object
// Therefore it logs the window object
Example event listeners:
document.querySelector('.foo').addEventListener('click', function () {
console.log(this); // This refers to the DOM element the eventListener was invoked from
})
document.querySelector('.foo').addEventListener('click', () => {
console.log(this); // Tip, es6 arrow function don't have their own binding to the this v
}) // Therefore this will log the global object
.foo:hover {
color: red;
cursor: pointer;
}
<div class="foo">click me</div>
Example constructor:
function Person (name) {
this.name = name;
}
const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object
console.log(me.name);
// Therefore, the name property was placed on the object created with new keyword.
To understand "this" properly one must understand the context and scope and difference between them.
Scope: In javascript scope is related to the visibility of the variables, scope achieves through the use of the function. (Read more about scope)
Context: Context is related to objects. It refers to the object to which a function belongs. When you use the JavaScript “this” keyword, it refers to the object to which function belongs. For example, inside of a function, when you say: “this.accoutNumber”, you are referring to the property “accoutNumber”, that belongs to the object to which that function belongs.
If the object “myObj” has a method called “getMyName”, when the JavaScript keyword “this” is used inside of “getMyName”, it refers to “myObj”. If the function “getMyName” were executed in the global scope, then “this” refers to the window object (except in strict mode).
Now let's see some example:
<script>
console.log('What is this: '+this);
console.log(this);
</script>
Runnig abobve code in browser output will:
According to the output you are inside of the context of the window object, it is also visible that window prototype refers to the Object.
Now let's try inside of a function:
<script>
function myFunc(){
console.log('What is this: '+this);
console.log(this);
}
myFunc();
</script>
Output:
Now let's create our own object. In javascript, you can create an object in many ways.
<script>
var firstName = "Nora";
var lastName = "Zaman";
var myObj = {
firstName:"Lord",
lastName:'Baron',
printNameGetContext:function(){
console.log(firstName + " "+lastName);
console.log(this.firstName +" "+this.lastName);
return this;
}
}
var context = myObj.printNameGetContext();
console.log(context);
</script>
Output:
So from the above example, we found that 'this' keyword is referring to a new context that is related to myObj, and myObject also has prototype chain to Object.
Let's go throw another example:
<body>
<button class="btn">Click Me</button>
<script>
function printMe(){
//Terminal2: this function declared inside window context so this function belongs to the window object.
console.log(this);
}
document.querySelector('.btn').addEventListener('click', function(){
//Terminal1: button context, this callback function belongs to DOM element
console.log(this);
printMe();
})
</script>
</body>
output: Make sense right? (read comments)
If you having trouble to understand the above example let's try with our own callback;
<script>
var myObj = {
firstName:"Lord",
lastName:'Baron',
printName:function(callback1, callback2){
//Attaching callback1 with this myObj context
this.callback1 = callback1;
this.callback1(this.firstName +" "+this.lastName)
//We did not attached callback2 with myObj so, it's reamin with window context by default
callback2();
/*
//test bellow codes
this.callback2 = callback2;
this.callback2();
*/
}
}
var callback2 = function (){
console.log(this);
}
myObj.printName(function(data){
console.log(data);
console.log(this);
}, callback2);
</script>
output:
Now let's Understand Scope, Self, IIFE and THIS how behaves
var color = 'red'; // property of window
var obj = {
color:'blue', // property of window
printColor: function(){ // property of obj, attached with obj
var self = this;
console.log('In printColor -- this.color: '+this.color);
console.log('In printColor -- self.color: '+self.color);
(function(){ // decleard inside of printColor but not property of object, it will executed on window context.
console.log(this)
console.log('In IIFE -- this.color: '+this.color);
console.log('In IIFE -- self.color: '+self.color);
})();
function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
console.log('nested fun -- this.color: '+this.color);
console.log('nested fun -- self.color: '+self.color);
}
nestedFunc(); // executed on window context
return nestedFunc;
}
};
obj.printColor()(); // returned function executed on window context
</script>
Output is pretty awesome right?