Here's a good way to understand this
(pun intended):
The value of this
inside a function is determined by the way the function is called. With one exception, it doesn't have to do with where the function is defined, what other functions it may be nested inside, what object it was defined as part of, what kind of function it is, or any of that.
When you call a function using a method call like foo.bar()
or foo[bar]()
, this
inside the function is the foo
object.
When you call a function with an ordinary function call like foo()
, this
in the function is the window
object, or if the function uses strict mode it is undefined
.
That's the one exception - if the function itself or its surrounding code has "use strict";
it changes this
for a plain function call. For good code that shouldn't make a difference - you shouldn't be writing code that depends on this
being the window
object anyway.
Otherwise, what you care about is what object this
refers to in a method call. And that's always determined by how the function is called, not how it's defined.
Let's go through your first example.
When you call a.b()
, you're calling b
as a method of the a
object. So inside the b
function, this
is the same as a
.
As it happens, it doesn't do us any good to know that, because the b
function never does anything with this
. All it does is call c()
as an ordinary function. So inside c
, this
is the window
object, or it would be undefined
if you were in strict mode.
The c
function simply returns its this
value, or window
. And that is also the return value from b
. So that's why you see window
as the result: it all comes from how the code calls the b
and c
functions.
Now about the second example: well, that's just terribly obfuscated code, isn't it? Who would ever write this code and expect anyone to understand it at first glance?
So let's turn it into a more readable form. This line is the problem:
return (function() {return this;})();
Let's take out the parenthesized function expression:
(function() {return this;})
and assign it to a temp variable:
var temp = (function() {return this;});
We don't need the extra parentheses any more, and let's indent the code for readability:
var temp = function() {
return this;
};
and we can call that temp
variable as a function in the return
statement:
return temp();
Now we can put this back into the b
function in the code example:
var a = {
b: function() {
var temp = function() {
return this;
};
return temp();
}
};
a.b(); //window
Hey! Doesn't that code look familiar? In fact, it's identical to the first example except for the name of the temp
variable. So now you see why it works the same as the first one.