31

Can anybody explain to me why A is true and B is false? I would have expected B to be true as well.

function MyObject() {

};

MyObject.prototype.test = function () {
    console.log("A", this instanceof MyObject);
    (function () {
        console.log("B", this instanceof MyObject);
    }());
}

new MyObject().test();

update: since ecmascript-6 you can use arrow functions which would make it easy to refer to MyObject like this:

function MyObject() {

};

MyObject.prototype.test = function () {
    console.log("A", this instanceof MyObject);
    (() => {//a change is here, which will have the effect of the next line resulting in true
        console.log("B", this instanceof MyObject);
    })(); //and here is a change
}

new MyObject().test();    
Coen
  • 4,586
  • 4
  • 21
  • 38
  • 8
    Welcome to functional scope in JavaScript. – zzzzBov Dec 29 '11 at 17:09
  • 1
    @zzzzBov: That's not a closure. – SLaks Dec 29 '11 at 17:09
  • You might want to use an additional pair of parens to improve readability: `( new MyObject() ).test()` – Šime Vidas Dec 29 '11 at 17:11
  • @SLaks, I've edited my comment to correctly reflect the usage of the anonymous function, although it *is* being used as a closure. – zzzzBov Dec 29 '11 at 17:11
  • 1
    No; it's not being used as a closure. It's not closing over anything. Scope is not really relevant. – SLaks Dec 29 '11 at 17:12
  • @zzzzBov Correct me if I'm wrong, but IIFE's can't form closures since they're invoked immediately. Only when a function survives (as a reference) the invocation of its outer function, only then we have a closure. – Šime Vidas Dec 29 '11 at 17:16
  • @ŠimeVidas: Wrong; using a variable in an IIFE still creates a closure. Even though it probably won't last beyond the parent scope, it's still a closure. Also, the IIFE could cause itself to be called later if it's named. – SLaks Dec 29 '11 at 17:18
  • @SLaks Assuming that it's a anonymous IIFE, that it doesn't declare any local variables, and that it doesn't contain any nested function declarations/expressions, would it be a closure in that case? (hypothetically speaking, unrelated to this question) – Šime Vidas Dec 29 '11 at 17:25
  • @ŠimeVidas: If it doesn't actually use any parent variables and doesn't call `eval`, it isn't a closure. – SLaks Dec 29 '11 at 17:26
  • @SLaks Ah yes, of course. If the function uses its scope chain (if it accesses any of its outer scopes), then it's a closure. – Šime Vidas Dec 29 '11 at 17:31
  • @ŠimeVidas, SLaks, could one of you provide a third party definition of "closure" that you feel acceptably describes closures in JavaScript? – zzzzBov Dec 29 '11 at 17:41
  • @zzzzBov I'm working on it in the [chat room](http://chat.stackoverflow.com/rooms/17) `:)` – Šime Vidas Dec 29 '11 at 17:44
  • @zzzzBov: See [this answer](http://stackoverflow.com/a/111200/21475) – Cameron Dec 29 '11 at 19:23
  • @Cameron, so what's the definition? closures don't need to be returned from some function in order to retain a reference to it outside of its original functional scope. My definition of a closure is **"any block that *closes* (retains, remembers, stores reference to, etc) over the variables previously in scope, and allows for instantiation of new variables without polluting the parent's scope"**. I'm sure it's a naive definition, but it's a start. – zzzzBov Dec 29 '11 at 19:33
  • @Cameron, [this answer states that all functions are closures in JS](http://programmers.stackexchange.com/questions/40454/what-is-a-closure). – zzzzBov Dec 29 '11 at 19:38
  • @zzzzBov: That's a good definition. However, instead of "previously in scope", I would say "from a parent scope". – SLaks Dec 29 '11 at 19:49
  • @zzzzBov: Right, they don't need to be returned, but the key is that a function isn't (technically) a closure until it leaves its parent's scope (and, of course, references variables in its parent's scope). – Cameron Dec 29 '11 at 20:58
  • Possible duplicate of [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Liam Nov 03 '17 at 16:27

4 Answers4

35

Inside of your anonymous function this is the global object.

Inside of test, this is the instance of MyObject on which the method was invoked.


Whenever you call a function like this:

somceFunction(); // called function invocation

this is always the global object, or undefined in strict mode (unless someFunction was created with bind** — see below)

Whenever you call a function like this

foo.someMethod();  //called method invocation

this is set to foo


**EcmaScript5 defines a bind function that allows you to create a function that has a pre-set value for this

So this

    var obj = { a: 12 };
    var someFunction = (function () { alert(this.a); }).bind(obj);
    someFunction();

Causes someFucntion to be invoked with this equal to obj, and alerts 12. I bring this up only to note that this is a potential exception to the rule I mentioned about functions invoked as

someFunction();

always having this equal to the global object (or undefined in strict mode)

Adam Rackis
  • 79,454
  • 49
  • 255
  • 377
  • The line `(function () { alert(this.a); }).bind(obj)` is exactly what I was looking for - binding context to an anonymous function. Works perfectly, +1 – jonny Mar 23 '16 at 11:17
  • you can also set the `this` using `func.call(this, arg1, arg2..)` – Omu Oct 31 '17 at 11:51
24

this is special. It refers to the object that the function is being called on behalf of (most commonly via dot syntax).

So, in the case of A, the function is being called on behalf of a new MyObject object. B is in a different function that isn't explicitly being called on behalf of any object, so this defaults to the global object (window).

In other words, this changes depending on how the function is called, not where or how it is defined. The fact that you're using an anonymous function (defined inside another function) is coincidental and has no effect on the value of this.

Cameron
  • 86,330
  • 19
  • 177
  • 216
  • 5
    Your statement "`this` changes depending on how the function is *called*, not where or how it is defined", can be misleading. In fact, `this` is simply the called function's owner - and that is in itself always either is explicitly defined or defaults to the global object. `myVar.doSomething = doSomething;` defines the function `myVar.doSomething` as `doSomething` where `this` will always refer to `myVar` when calling `myVar.doSomething()`, regardless of where `myVar.doSomething()` is called from. Your statement might suggest otherwise. – Navigateur Dec 15 '13 at 10:53
8

In the anonymous function, this is bound to the global object (window in a browser environment).

There are various ways of accessing the instance:

var self = this;
(function () {
    console.log("B", self instanceof MyObject);
}());

or

(function () {
    console.log("B", this instanceof MyObject);
}).call(this);
ThiefMaster
  • 285,213
  • 77
  • 557
  • 610
3

this is set based on how you call the function.
Your anonymous function is a normal function call, so this is the global object.

You could write (function() { ... }).call(this) to explicitly call it with your this.

SLaks
  • 800,742
  • 167
  • 1,811
  • 1,896