I thought I had a reasonable understanding of the this
object in JavaScript. When dealing with objects, callbacks, and both events and handlers, I haven't had a problem with it since time immemorial. Now, however, all has changed.
I've fallen head over heels in love with JavaScript. Pure JS, that is, not jQuery, prototype.js, dojo... So naturally, I've taken to using closures. In some cases, though, this
is catching me off guard here. Take this snippet for one:
function anyFunc(par)
{
//console.log(par);
console.log(this);
}
function makeClosure(func)
{
return function(par)
{
return func(par);
}
}
var close = makeClosure(anyFunc);
close('Foo');
var objWithClosure = {cls:makeClosure(anyFunc),prop:'foobar'};
objWithClosure.cls(objWithClosure.prop);
var scndObj = {prop:'Foobar2'};
scndObj.cls = makeClosure;
scndObj.cls = scndObj.cls(anyFunc);
scndObj.cls(scndObj.prop);
In all three cases, this
logs as the window object. It's an easy fix, of course:
function makeClosure(func)
{
return function(par)
{
return func.call(this,par);
}
}
This fix works, I put it here to avoid people answering this, without explaining what I need to know: why is this behaving the way it does here?
ensures the caller is effectively the object that the closure belongs to. What I fail to understand is this:
Sure enough, this
points to the window object in the first case, but in other cases, it shouldn't. I tried logging this
in the makeClosure function just before returning, and it did log the object itself, not the window
object. But when the actual closure is used, this
is back to pointing to the window object. Why?
The only thing I can think of is that, by passing the anyFunc
function as an argument, I'm actually passing window.anyFunc
. So I tried this quick fix:
function makeClosure(func)
{
var theFunc = func;
return function(par)
{
theFunc(par);
}
}
With the expected results, this
now points to the objects, but again: Why? I have a few idea's (theFunc
is a reference to the function in the local scope [this > private: theFunc
]?), but I'm sure there are people here with a lot more know-how when it comes to JS, so I was hoping to get some more explanation or links to articles worth reading from them...
Thanks
Update
Here's a fiddle, may be I left something out, but here this logs all sorts of things ;)
Edit/Update 2
The case that confuses me is here.
Final Edit
Ok, This is getting a rather messy post. So to clarify: What I was expecting was a behaviour similar to this:
function makeClosure()
{
function fromThisFunc()
{
console.log(this);
}
return fromThisFunc;
}
var windowContext = makeClosure();
windowContext();
var objectContext = {cls:makeClosure()};
objectContext.cls();
What caught me, was that the function anyFunc
wasn't declared within the correct scope, and therefore, this
pointed to the window object. I found this out by reading an ancient scroll I found somewhere on the web.
But something a little more complicated has happened because the function object now referred to by globalVar was created with a [[scope]] property referring to a scope chain containing the Activation/Variable object belonging to the execution context in which it was created (and the global object). Now the Activation/Variable object cannot be garbage collected either as the execution of the function object referred to by globalVar will need to add the whole scope chain from its [[scope]] property to the scope of the execution context created for each call to it.
So what I needed to do, was simplify rather then complicate things:
function fromThisFunc()
{
console.log(this);
}
function makeClosure(funcRef)
{
//some code here
return funcRef;
}
That should work, right?
PS: I'll except Alnitak's answer, but special thanks goes to Felix Kling for all the patience and info.
As soon as you call:
You're creating a new scope (with its own
this
) and in this case because you haven't specified an object,this === window
usually or undefined in strict mode. The called function does not inherit whateverthis
was in the calling scope.Ways to set a value for this are:
or
There are also:
The value of
this
depends only on whether you call the function as a method or as a function.If you call it as a method,
this
will be the object that the method belongs to:If you call it as a function,
this
will be thewindow
object:Note that even if you are in a method that belongs to an object, you still have to call other methods in the object using the method syntax, otherwise they will be called as functions:
If you put a method reference in a variable, you will detach it from the object, and it will be called as a function:
The
call
andapply
methods are used to call a function as a method even if it's not a method in the object (or if it's a method in a different object):