7

Ok, so I thought I understood this (no pun intended), but apparently not.

var Constructor = function () {
    var internalFunction = function () {
        return this === window;
    };
    this.myMethod = function () {
        alert(internalFunction());
    };
};
var myObj = new Constructor();
myObj.myMethod();

This alerts true. Why can't the internal function see this as the object? Instead I have to use alert(internalFunction.call(this)); in myMethod.

Edit: I was looking for an explanation as to why this is assigned in that way, not workarounds such as var self = this;, etc. Sorry if I didn't make that clear.

Nathan MacInnes
  • 11,033
  • 4
  • 35
  • 50

4 Answers4

6

this is not bound until the function is called and is dependent on how the function is called. You could think of it as an extra parameter implicitly passed to the function.

In this case, the problem is that you're calling internalFunction using internalFunction(). The this value is set either by calling a function as a method (as in foo.bar() or foo["bar"]()) or by setting this explictly via call() or apply(). Your call is doing neither so this reverts to the global object.

The simplest way to achieve what you want in this case while keeping internalFunction private is to store a reference to this inside the constructor function:

var Constructor = function() {
    var thisObj = this;

    var internalFunction = function () {
        return thisObj === window;
    };

    thisObj.myMethod = function () {
        alert(internalFunction());
    };
}
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Ah, that makes sense... `this` is assigned at call-time, so by calling `internalFunction()` I'm implicitly calling `window.internalFunction()`. Well explained. – Nathan MacInnes Nov 02 '11 at 14:44
  • @jondavidjohn: I'm not getting into a discussion on that and it was a needless tweak to the original code on my part, so I've reverted it. Thanks for pointing it out. – Tim Down Nov 02 '11 at 14:48
3

Because of functional scoping rules, this is reassigned inside each function... I would store a copy of your object as self and use it accordingly...

var Constructor = function () {

    var self = this;

    var internalFunction = function () {
        return self === window;
    };
    this.myMethod = function () {
        alert(internalFunction());
    };
};
var myObj = new Constructor();
myObj.myMethod();

Should give you the output you expect.

SIDENOTE

This is a fairly precarious practice that javascript has created, mainly because if you forget the new keyword when using Constructor, you will get this referring to the window (god) object so you'll be attaching myMethod to the window without warning.

jondavidjohn
  • 61,812
  • 21
  • 118
  • 158
2

There are five ways to call a function in JavaScript. The value of this depends on which you choose:

  1. Global function call (e.g. myFunction()). No explicit value for this is given. The value of this will be the default object (window in a browser).
  2. Method call (e.g. obj.myFunction()). The value of this is the object on which the method was invoked (obj in this case).
  3. Using the call method (e.g. myFunction.call(obj)). The value of this is provided explicitly (in this case obj).
  4. Using the apply method (e.g. myFunction.apply(obj)). The value of this is provided explicitly (in this case obj).
  5. Constructor function (e.g. new MyFunction()). The value of this is a newly-created object provided by the runtime.

Each of the five is explained in more detail here:

Wayne
  • 59,728
  • 15
  • 131
  • 126
1

Its a scope issue try something like:

var Constructor = function () {
    var $this = this;
    var internalFunction = function () {
        return $this === window;
    };
    this.myMethod = function () {
        alert(internalFunction());
    };
};
var myObj = new Constructor();
myObj.myMethod();
John Hartsock
  • 85,422
  • 23
  • 131
  • 146