1

When initially invoking a function, the first this within the first function that is called refers to the parent object foo but on a subsequent function called by that first function this refers to the window object?

var foo = (function Obj(){
    var t = this;
    return  {
        getThis: getThis,
        getSecondThis: getSecondThis
    };
    function getThis(){ 
        console.log(this);
        console.log(t);
        getSecondThis()
        return false;
    }
    function getSecondThis(){ 
        console.log(this);
        console.log(t);
        return false;
    }
})();

foo.getThis();

If I change the call from getSecondThis() to this.getSecondThis() then the this within getSecondThis() refers to the parent object foo see the code below

var foo = (function Obj(){
    var t = this;
    return  {
        getThis: getThis,
        getSecondThis: getSecondThis
    };
    function getThis(){ 
        console.log(this);
        console.log(t);
        this.getSecondThis() //line edited
        return false;
    }
    function getSecondThis(){ 
        console.log(this);
        console.log(t);
        return false;
    }
})();

foo.getThis();

The getSecondThis() is within the scope of the parent object foo but window is returned when this is not specified on the second call.

Aaron
  • 3,195
  • 5
  • 31
  • 49
  • Put `"use strict";` before the `var` declaration in the outer anonymous function and see what happens. – Pointy Jul 23 '14 at 14:22
  • Right. In "strict" mode, a function invoked with no context will see `this` set to `undefined`. In "sloppy" (default, for now) mode, in such cases `this` is the global (`window`) object. – Pointy Jul 23 '14 at 14:32
  • See my answer here for a full description of how "this" works in javascript: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 – slebetman Jul 24 '14 at 07:28

1 Answers1

2

It's just the way JS binds the calling context: JS binds the context (the this reference) ad-hoc. Meaning: depending on how, where and by what means it is invoked, this will reference a different object.
I've explained this in some detail before here, and in the linked answers found on the bottom

Basically, functions are first class objects, meaning that, like any value, you can assign a function to a multitude of variables/properties. Of course, if you assign a function to an object (as a property), that function is often referred to as a method, and you'd expect this to point to the object that owns that method.
However, as Pointy noted in the comments: An object cannot own another object. Objects can be referenced by one or more properties of another object.

JS will kindly set this to refer to the object that owns the function. But if you then assign the object to a variable, it would make no sense to have this point to that same object. Think of situations where you're passing functions as function arguments (callbacks in jQuery and so on). You probably want this to reference the new context (certainly the case in jQ event handlers!). If no context is provided, JS sadly defaults the this reference to the global object.

You can explicitly bind a function to a given context using the Function.prototype.bind call.
If you want to specify the context for a single call, you can use Function.prototype.call(context, arg1, arg2); or Function.prototype.apply(context, [args]);

Most larger projects (toolkits like jQ for example) solve this issue by taking advantage of closure scoping. Using the module pattern, for example, is a common, and easy way to control the context. I've explained this, too, complete with graphs to illustrate what is going on :)

Some examples/puzzles to make this easier to follow or more fun:

var obj = (function()
{//function scope
    'use strict';//this will be null, instead of global, omit this and this can be window
    var obj = {},
        funcOne = function()
        {
            console.log(this, obj, this === obj);
            funcTwo(this);
            obj.funcTwo();
            obj.funcTwo(this);
            obj.funcTwo(obj);
        },
        funcTwo = function(that)
        {
            console.log(this, obj, this === obj, this === that, that === obj);
        };
        obj.funcOne = funcOne;
        obj.funcTwo = funcTwo;
        return obj;//is assigned to the outer var
}());
obj.funcOne();
//output:
//- first logs itself twice, then true
//then calls made in funcOne:
funcTwo()
console.log(this, obj, this === obj, this === that, that === obj);
//- this: undefined (omit 'use strict' and it'll be window), obj,
//     this === obj => false, this === that => false, that === obj => true
obj.funcTwo();
console.log(this, obj, this === obj, this === that, that === obj);
//logs obj twice, because obj.funcTwo means the context === obj
//this === obj is true (of course)
//that is undefined, so this === that and that === obj are false
//lastly
obj.funcTwo(this);
obj.funcTwo(obj);

You should be able to work that out. You know the context in which funcOne is being executed, and you know what the effects are of invoking funcTwo as a method of obj

Rule of thumb:
I hesitated to write this, because it's far from accurate, but 8/10 cases. Assuming no code has been meddling with contexts through bind, call, and apply, you can work out the context using this trick:

someObject.someMethod();
    /\        ||
    |===this===|
//another object:
var obj2 = {
    borrowed: someObject.someMethod,
    myOwn: function()
    {
        this.borrowed();
    }
};
obj2.myOwn();//this === obj2 (as explained above),
   \\
    \==> this.borrowed === obj2.borrowed 
            \\
             \==> ~= someObject.someMethod.call(obj2);//function is executed in context of obj2
//simple vars
var alias = someObject.someMethod;//assign to var
alias();//no owner to be seen?
   ||
?<==|
//non-strict mode:
[window.]alias();
 /\ implied ||
 ||         ||
 |==<this>===|
//strict mode
alias.call(undefined);//context is undefined
Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • @Aaron: I'm sorry, it's not really that difficult, but I'm, perhaps, not quite the best tutor. It took me some time to understand how JS's `this` binding worked, too, but all of a sudden, it hit me. The second link (with the images) really helped me to understand closures – Elias Van Ootegem Jul 23 '14 at 14:34
  • @Aaron: Added a very concise, basic, and incomplete rule of thumb. It's not accurate 100% of the time, but it does apply to your situation, and it _does_ help to get an understanding of what is happening, IMHO – Elias Van Ootegem Jul 23 '14 at 14:42
  • @EliasVanOotegem this is a great explanation, but the idea that an object "owns" a method is a little suspicious to me, as there really is no inherent relationship between a function and any object. If properties on two different object refer to a single function, which "owns" it? Maybe I'm being too pedantic :) – Pointy Jul 23 '14 at 15:22
  • @Pointy: You're quite right. I'll edit to something along the lines of _"an object owns a property, that is assigned a reference to a function object"_. It might be more confusing to the OP, but it is more accurate – Elias Van Ootegem Jul 24 '14 at 07:19