BrainLikeADullPencil
BrainLikeADullPencil

Reputation: 11653

what does 'this' refer to in Javascript functions

I understand the general idea behind the this keyword but I'm having trouble figuring out what it actually refers to in practice. For example, in both these example exercises, I guessed the wrong number.

for question1, I said that the alert would be '5', because it is referring to the this.x outside the anonymous function in the function.

In question2, I thought the alert would be 5 because this line

var alertX = o.alertX;

would bind the value 5 for property x inside the variable o to the new variable 'alertX' which becomes the function call in the next line: alertX();

Can you explain why I'm wrong?

var question1 = function() {
    this.x = 5;
     (function() {
        var x = 3;
        this.x = x;
    })();
    alert(this.x);
};
var answer1 = 3; 


var question2 = function() {
    this.x = 9;
    var o = {
        'x':5,
        'alertX':function() { alert(this.x); }
    };
    var alertX = o.alertX;
    alertX();
}
var answer2 = 9; 

Upvotes: 7

Views: 1013

Answers (3)

Mark Pieszak - Trilon.io
Mark Pieszak - Trilon.io

Reputation: 66971

These are good examples of how interesting this becomes in Javascript. this always refers to the context in which it was invoked / called, not simply where it is at that moment! question2 is a perfect example of it.

I'm assuming you are invoking these globally like so:

question1();
question2();

In question1:

You have an anonymous function that is ran after you first set x to 5. This anonymous function if not set to a variable, inside a function etc, would have this set to the global variable of window. But you have it within a function & set to variable question1. So when it runs itself, it sets this's (which is question1 function) x variable to 3.

In question2:

X is originally set to 9, this being question2 in this instance. Now the part that is throwing you off is that, even though within the o {} object you set x : 5. And your alertX function is calling this.x. All of this would lead you to think it will alert 5! But you are invoking your alert function outside of the o {} object, hence the this refers to question2 function again!

Upvotes: 0

Paul S.
Paul S.

Reputation: 66324

Put the following into your browser's console

var x = -1, log = function(){ // set up some stuff
if(console) if(console.log) return console.log.apply(console, arguments),undefined;
return alert(arguments.join(', ')),undefined;
},
question1 = function() {
    this.x = 5; // question1.x is 5
     (function() { // anonymous function fires in global 'window'
        var x = 3; // so window.x is now 3
        this.x = x; // this is window
    })();
    log('ans1',this.x,this); // see below
},
question2 = function() {
    this.x = 9; // question2.x is 9
    var o = {
        'x':5,  // o.x is 5
        'alertX':function() { log('ans2',this.x,this); }
    };
    var alertX = o.alertX; // alertX === o.alertX
    alertX(); // being called in global scope

    // to make alertX have scope of question2
    this.alertX = o.alertX; // this is question2
    this.alertX(); // so we're calling from question2
},
a1 = new question1(), // note the new operator
a2 = new question2();
undefined;

And you'll get

ans1 5 question1
ans2 3 Window
ans2 9 question2

Upvotes: 0

Phrogz
Phrogz

Reputation: 303206

In the first case, when you invoke a method with no explicit receiver this is the Global object (the window in a web browser).

Similarly in the second case: even though the function is defined on the object, and you are inside another, by invoking the function with alertx() the this is set to the Global/window.

In short:

  • For foo.bar(), the this inside of bar will be foo.
  • For bar(), the this will be the Global object.
    • This includes so-called "self-invoking lambdas", i.e. (function(){ ... })().
  • For bar.call(whee) and bar.apply(whee), the this will be whee (because that's what these methods do).

Another example:

var o1 = { name:"o1", f:function(){ console.log(this.name) } };
var o2 = { name:"o2" };
o2.gogogo = o1.f;
o2.gogogo(); // Will output "o2"

Upvotes: 3

Related Questions