5

When I run the below IFFE, why does the this keyword refer to the window object and not to a variable?

var a = {
 printThis : function () {
 console.log('printThis', this);
  var inner = (function () {
    console.log('inner', this);
   })();
  }
};

a.printThis(); 

Result in the following output:

printThis **an object**

inner **window object**   <-- why..?

var a = {
  printThis: function() {
    console.log('printThis', this);
    var inner = (function() {
      console.log('inner', this);
    })();
  }
};

a.printThis();
j3ff
  • 4,539
  • 5
  • 35
  • 45
Mr. A
  • 67
  • 1
  • 8
  • You are not calling `a.inner()`, just `inner()`. So `a` won't become `this`. – Thilo May 27 '16 at 10:29
  • But it is inside a then too.. – Mr. A May 27 '16 at 10:30
  • Doesn't matter. Every function gets their own `this`. If you want to keep the outer `this`, you have to use `bind` or `var self = this` or "fat arrow". – Thilo May 27 '16 at 10:32
  • Can you please explain how this is working for JavaScript engine..? – Mr. A May 27 '16 at 10:33
  • 1
    Possible duplicate of [How does the "this" keyword work?](http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Thilo May 27 '16 at 10:34
  • That is becomes `window` (the global object) is a legacy artefact. In strict mode, it will be `undefined`. – Thilo May 27 '16 at 10:36
  • BTW - it's IIFE - Immediately Invoked Function Expression – phuzi May 27 '16 at 10:42
  • Also have a look at [How does the `this` keyword work within a JavaScript object literal?](http://stackoverflow.com/q/133973/1048572) for why it won't refer to `a` – Bergi May 27 '16 at 10:56

1 Answers1

12

Consider the following example:

var a = {};
var b = {};
a.hello = function() { console.log(this); };
b.hello = a.hello;

In most programming languages, b.hello() would print a since they base this on where the function is. The function is in a, so this is a. Makes sense, right?

However, JavaScript is a bit different in that regard. Instead of where it is, it's based on how it was called. b.hello() calls hello on b, thus this is set to b. This also makes sense since JavaScript doesn't really have a concept of "where" a function is (unlike methods in, say, Java, which are always tied to a specific class), and it's hard to determine that a is where it "is".

So, foo.bar() will always set this to foo for the purposes of this call to bar (unless one has used bind or similar to bind this to a specific value in advance).

Now, an IIFE is invoked on... nothing, really. It's not a foo.bar() situation, it's just a bar() where bar is your function expression. In cases like this where there's no foo, it defaults to the window object.

There are two simple workarounds:

  1. Create a variable outside the IIFE containing the value you´re interested in: var that = this; and use that instead of this in the IIFE, or
  2. bind the this value: (function(){ CODE GOES HERE }).bind(this)();
BambooleanLogic
  • 6,088
  • 2
  • 26
  • 51
  • Before reading this answer, I was about to *flip this table in frustration*, but I couldn't figure out what *this* even was! – Scribblemacher Sep 16 '19 at 14:40