0

I have the following code:

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

This outputs:

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

I understand this occurs because the IIFE's this refers to the global scope, not myObject. But why does it refer to the global scope? How come IIFE's this variable refers to the global scope?

chopper draw lion4
  • 9,509
  • 12
  • 45
  • 85
  • Douglas Crockford's Javascript: The Good Parts was a huge help to me in understanding JS's function scope quirks. http://it-ebooks.info/book/274/ – Larry Turtis Apr 05 '15 at 22:44
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this has a pretty good explanation. – mrmcgreg Apr 05 '15 at 22:54

2 Answers2

3

Because that's how JS functions work. If you don't implicitly (via object.method() syntax) or explicitly (via .call, .apply or .bind) set the value of this, it defaults to the global object, unless you're in strict mode.

So if you took an IIFE, and used .call, passing it a different object, you'd get that object as the this value.

    (function() {
        console.log("inner func:  this.foo = " + this.foo); // "bar"
        console.log("inner func:  self.foo = " + self.foo);
    }).call({foo: "bar"});
2

Any function call in Javascript resets the value of this according to how the function was called. An IIFE is such a function call.

So, if you don't call that function in any special way, the value of this will be set to window in regular mode in a browser or undefined in strict mode. That is how Javascript handles this when making a normal function call.

As a surprise to many, there is no concept of "preserving" the current value of this when you call a function in Javascript. You would have to call it a specific way to set the value of this if you want to control it.

In your code, you could preserve the value of this by using .call() with the IIFE like this:

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);
        }).call(this);
    }
};

Working demo: http://jsfiddle.net/jfriend00/66cL4zt5/

See this reference for a summary of all the ways that this is set.

Community
  • 1
  • 1
jfriend00
  • 580,699
  • 78
  • 809
  • 825