Ponteiro "this" do Javascript dentro de função aninhada
Eu tenho uma pergunta sobre como o ponteiro "this" é tratado em um cenário de função aninhada.
Digamos que eu insira o seguinte código de exemplo em uma página da web. Recebo um erro quando chamo a função aninhada "doSomeEffects()". Verifiquei no Firebug e ele indica que quando estou nessa função aninhada, o ponteiro "this" na verdade está apontando para o objeto global "window" - o que eu não esperava. Eu devo não estar entendendo algo corretamente porque pensei que, como declarei a função aninhada dentro de uma função do objeto, ela deveria ter escopo "local" em relação à função (ou seja, o ponteiro "this" se referiria ao próprio objeto, assim como está na minha primeira declaração "if").
Qualquer dica (sem trocadilho intencional) seria apreciada.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
Resposta #1
Em JavaScript, o objeto this realmente depende de como você faz suas chamadas de função.
Em geral, existem três maneiras de configurar o objeto this:
someThing.someFunction(arg1, arg2, argN)someFunction.call(someThing, arg1, arg2, argN)someFunction.apply(someThing, [arg1, arg2, argN])
Em todos os exemplos acima, o objeto this será someThing. Chamar uma função sem um objeto pai à frente geralmente fará com que você obtenha o objeto global, o que na maioria dos navegadores significa o objeto window.
Resposta #2
Como esta parece ser uma das perguntas mais votadas desse tipo, deixe-me adicionar, depois de todos esses anos, a solução em ES6 usando funções arrow:
var std_obj = {
...
displayMe() {
...
var doSomeEffects = () => {
^^^^^^^ ARROW FUNCTION
// In an arrow function, the 'this' pointer is interpreted lexically,
// so it will refer to the object as desired.
if (this.activeEffect=="fade") { }
};
...
}
};
Resposta #3
this não faz parte do escopo da closure, pode ser pensado como um parâmetro adicional para a função que é vinculado no local da chamada. Se o método não for chamado como um método, então o objeto global é passado como this. No navegador, o objeto global é idêntico a window. Por exemplo, considere a seguinte função,
function someFunction() {
}
e o seguinte objeto,
var obj = { someFunction: someFunction };
Se você chamar a função usando a sintaxe de método, como,
obj.someFunciton();
então this está vinculado a obj.
Se você chamar someFunction() diretamente, como,
someFunction();
então this está vinculado ao objeto global, ou seja, window.
A solução alternativa mais comum é capturar isso no closure, como,
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var that = this;
var doSomeEffects = function() {
// the 'this' pointer is referring to global
// that, however, refers to the outscope this
if (that.activeEffect=="fade") { }
}
doSomeEffects();
}
Resposta #4
Para entender esta questão, tente obter a saída do seguinte trecho
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
};
myObject.func();
O código acima exibirá o seguinte no console:
outer func: this.foo = bar
outer func: self.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar
Na função externa, tanto this quanto self se referem a myObject e, portanto, ambos podem referenciar e acessar foo corretamente.
Na função interna, porém, isso não se refere mais a myObject. Como resultado, this.foo é indefinido na função interna, enquanto a referência à variável local self permanece no escopo e é acessível lá. (Antes do ECMA 5, this na função interna se referiria ao objeto global window; enquanto, a partir do ECMA 5, this na função interna seria indefinido.)
Resposta #5
Há uma diferença entre variáveis de fechamento e "this". "this" é na verdade definido pelo invocador da função, enquanto variáveis explícitas permanecem intactas dentro do bloco de declaração da função conhecido como fechamento. Veja o exemplo abaixo:
function myFirstObject(){
var _this = this;
this.name = "myFirstObject";
this.getName = function(){
console.log("_this.name = " + _this.name + " this.name = " + this.name);
}
}
function mySecondObject(){
var _this = this;
this.name = "mySecondObject";
var firstObject = new myFirstObject();
this.getName = firstObject.getName
}
var secondObject = new mySecondObject();
secondObject.getName();
você pode experimentá-lo aqui: http://jsfiddle.net/kSTBy/
O que está acontecendo na sua função é que "doSomeEffects()" está sendo chamado explicitamente, isso significa que o contexto ou o "this" da função é a window. Se "doSomeEffects" fosse um método de protótipo, por exemplo, this.doSomeEffects em, digamos, "myObject", então myObject.doSomeEffects() faria com que "this" fosse "myObject".
