120

I have a question concerning how the "this" pointer is treated in a nested function scenario.

Say I insert this following sample code into a web page. I get an error when I call the nested function "doSomeEffects()". I checked in Firebug and it indicates that when I am in that nested function, the "this" pointer is actually pointing to the global "window" object - which I did not expect. I must not be understanding something correctly because I thought since I declared the nested function within a function of the object, it should have "local" scope in relation to the function (i.e. the "this" pointer would be referring to the object itself like how it is in my first "if" statement).

Any pointers (no pun intended) would be appreciated.

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();
Evan Carslake
  • 2,267
  • 15
  • 38
  • 56
JoJoeDad
  • 1,711
  • 3
  • 16
  • 15
  • What exactly is your question ? – Sarfraz Mar 10 '12 at 05:03
  • 2
    When used inside a function, `this` refers to the object on which the function is invoked. – approxiblue Mar 10 '12 at 05:04
  • 9
    What you could do in the outer scope is something like `var self = this;` and then refer to `self` in the inner function via closure. – Kai Mar 10 '12 at 05:05
  • 1
    `doSomeEffects` is not associated with any obj in particular, so `this` is assumed to be the window, the mother of all elements. – approxiblue Mar 10 '12 at 05:05
  • Thanks everyone for your answers below. They are all awesome and well explained. I understand now. Thanks again! – JoJoeDad Mar 10 '12 at 05:25
  • 3
    @JoJoeDad How do I diplomatically say this? But the answer given by chuckj below is by far the answer to your question. To truly understand what is going on, you should read [execution context](http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/), [scope chain](http://davidshariff.com/blog/javascript-scope-chain-and-closures/) and [this keyword](http://davidshariff.com/blog/javascript-this-keyword/). And from the looks of some of the answers here, other people should read them too. I try to evangelize good javascript. That is why I am taking the time to give these links. – onefootswill Nov 02 '13 at 06:05
  • @onefootswill Popular is the new right. But thanks for the links. Really appreciate them. – 0fnt Oct 13 '14 at 05:43

9 Answers9

132

In JavaScript the this object is really based on how you make your function calls.

In general there are three ways to setup the this object:

  1. someThing.someFunction(arg1, arg2, argN)
  2. someFunction.call(someThing, arg1, arg2, argN)
  3. someFunction.apply(someThing, [arg1, arg2, argN])

In all of the above examples the this object will be someThing. Calling a function without a leading parent object will generally get you the global object which in most browsers means the window object.

KylePDavis
  • 1,730
  • 1
  • 13
  • 6
  • I changed the code to `this.doSomeEffects();` based on your answer but still it does not work. Why? – Arashsoft Jul 17 '18 at 15:28
  • 1
    @Arashsoft `this` in `this.doSomeEffects()` points to `std_obj`. As explained in the answer above if a function doesn't have object reference then it takes `this` to be a window object. – Shivam Jun 28 '19 at 18:46
63

Since this appears to be among the most upvoted questions of its kind, let me add, after all these years, the ES6 solution using arrow functions:

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") { }
    };
    ...    
  }
};
37

this is not part of the closure scope, it can be thought of as an additional parameter to the function that is bound at the call site. If the method is not called as a method then the global object is passed as this. In the browser, the global object is identical to window. For example, consider the following funciton,

function someFunction() {
}

and the following object,

var obj = { someFunction: someFunction };

If you call the function using method syntax such as,

obj.someFunciton();

then this is bound to obj.

If you call someFunction() directly, such as,

someFunction();

then this is bound to the global object, that is window.

The most common work around is to capture this into the closure such as,

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();         
 }      
chuckj
  • 27,773
  • 7
  • 53
  • 49
12

To understand this question , try to get the output for the following snippet

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();

The above code will output the following to the console:

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

In the outer function, both this and self refer to myObject and therefore both can properly reference and access foo.

In the inner function, though, this no longer refers to myObject. As a result, this.foo is undefined in the inner function, whereas the reference to the local variable self remains in scope and is accessible there. (Prior to ECMA 5, this in the inner function would refer to the global window object; whereas, as of ECMA 5, this in the inner function would be undefined.)

ronakshah725
  • 290
  • 3
  • 10
11

There's a difference between enclosure variables and "this". "this" is actually defined by the invoker of the function, while explicit variables remain intact inside the function declaration block known as the enclosure. See the example below:

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();

you can try it out here: http://jsfiddle.net/kSTBy/

What's happening in your function is "doSomeEffects()", is being called explicitly, this means context or the "this" of the function is the window. if "doSomeEffects" was a prototype method e.g. this.doSomeEffects on say "myObject", then myObject.doSomeEffects() would cause "this" to be "myObject".

Shane
  • 4,921
  • 5
  • 37
  • 53
  • 5
    for the lazy and impatient, this demo logs: `_this.name = myFirstObject this.name = mySecondObject` – ptim Oct 16 '14 at 07:41
4

As explained by Kyle, you could use call or apply to specify this within the function:

Here is that concept applied to your code:

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.apply(this,[]);
    }
};

std_obj.displayMe();

JsFiddle

Hari Pachuveetil
  • 10,294
  • 3
  • 45
  • 68
0

Since it wasn't mentioned I will mention that using .bind() is a solution -


        doSomeEffects=doSomeEffect.bind(this);
        doSomeEffects();   
      }
    };

    std_obj.displayMe();

Here is a more simple example -

bad = { 
  name:'NAME', 
  z : function() { 
    function x() { console.log(this.name); }; 
    x() 
  } 
};
bad.z() // prints 'undefined'

good = { 
  name:'NAME', 
  z : function() { 
    function x() { console.log(this.name); }; 
    x=x.bind(this);
    x();
  } 
};
good.z() // prints 'NAME'

It is true that using an arrow function => looks slicker and is easy for the programmer. However, it should be kept in mind that a lexical scope is likely to require more work in terms of processing and memory to setup and maintain that lexical scope, compared to simply associating a function's this with a pointer via .bind().

Part of the benefit of developing classes in JS was to provide a method to make this more reliably present and available, to pivot away from functional programming and lexical scopes, and thus reduce overhead.

From MDN

Performance considerations It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.

Craig Hicks
  • 2,199
  • 20
  • 35
0

It's because "this" refers to the self object / local function.

var std_obj = {
  options : { rows: 0, cols: 0 },
  activeEffect : "none",
  displayMe : function() {

    if (this.activeEffect=="fade") { }

    let This = this; // 'this' here is for the std_obj scope. Create a reference to 'this' if you want to use it elsewhere.

    var doSomeEffects = function() {
      // 'this' here refers to the doSomeEffects scope. If you don't want "this," you can still use "this" of the std_obj scope.

      if (This.activeEffect=="fade") { }

    }

    doSomeEffects();   
  }
};

std_obj.displayMe();
Ahmad Zuhair
  • 39
  • 1
  • 4
-1

I also got a warning "Potentially invalid reference access to a class field via this"

class MyListItem {
    constructor(labelPrm) {
        this._flagActive = false;
        this._myLabel = labelPrm;
        labelPrm.addEventListener('click', ()=>{ this.onDropdownListsElementClick();}, false);
    }

    get myLabel() {
        return this._myLabel
    }
    get flagActive(){
        return this._flagActive;
    }

    onDropdownListsElementClick(){console.log("Now'this'refers to the MyListItem itself")}}//end of the class
CodeToLife
  • 3,672
  • 2
  • 41
  • 29