I haven't used Javascript in a long time and have been refreshing myself on it today. One thing that always got me was the this
keyword. I know in jQuery event handlers, such as the click event, this
refers to the element that fired the event. How is this
passed to the function that I give it as a callback even though my function has no arguments?
Given the following code:
$("tr.SummaryTbRow").data("Animating", false);
$("tr.SummaryTbAltRow").data("Animating", false);
$("tr.SummaryTbRow").click(function () {
if ($(this).data("Animating") == false) {
if ($(this).next(".Graph").css("display") == "none") {
$(this).data("Animating", true);
//Part I am questioning.
setTimeout(function () {
$(this).data("Animating", false);
}(this), 550);
$(this).next(".Graph").slideRow('down', 500);
}
else {
$(this).data("Animating", true);
$(this).next(".Graph").slideRow('up', 500);
}
}
});
I am trying to figure out how to pass the element table row with class SummaryTbRow
to my setTimeout call back function. Does jQuery pass this
in a similar fasion to what I am doing with my anonymous call back function? Does my this
inside the function refer to the this
I pass in?
I know I could just do:
setTimeout(function (element) {
$(element).data("Animating", false);
}(this), 550);
But I want to figure out how jQuery is able to pass this
to my call back function even though my function takes 0 arguments.
Short answer:
You can set
this
on a function by using the function's.call()
and.apply()
methods.Long answer:
The
this
variable on any function is similar to thearguments
variable (which is probably something you didn't know about). It's set when the function is called and is an artifact of how the function is called. To explain, let me start with a demonstration ofarguments
. Consider:Now let's look at a couple calls to
myFunction
:As you can see, the value of
arguments.length
is not dependent on how or where we wrote the function, but on how we called the function. The same is true of thethis
variable (otherwise known as the "calling object"). There are exactly 3 methods for setting the calling object (there's a sort-of 4th in ES5, but we'll ignore that):something.myFunction()
).call()
or.apply()
methods (e.g.myFunction.call(someObject)
)window
)So most people are used to method #1. If you assign your function as a property of an object, then call the function using the object and dot-notation, then the object gets set as
this
. Like so:But we can also use method 2 if
myFn
isn't a property of the object we want to call it on but the object follows the correct form formyFn
to be able to act on it (see: duck typing):Pretty cool, eh? This is how jQuery does it. When they execute your callback, they do so using
.apply(event.target)
(settingthis
to the event's target object). They do it in a more complex manner because of theircallbacks
framework, but the idea is there.Anyway, I wouldn't be offering a long answer if I didn't toss in an explanation of method #3, which drives some people totally insane: What happens if you don't set the calling object?
Because all global variables are implicit properties of the global object, you get some interesting effects from method #3. Such as:
But most of the time you're not lucky enough to have your global object meet the requirements the function has for its calling object, so usually it just results in an error and a lot of frustration.
Probably more than you were looking for, but hopefully you're now much more informed on the calling object and its wily ways.
Apply, call and bind methods serve for that purpose. In your case you just write:
You can call a function using
fn.call
orfn.apply
both of which take a context argument which is used forthis
.To answer you last question, you may pass the receiver of your choice to a function in javascript using for exemple call :
Inside
someFunction
,this
will besomeObject
.In your case, what you seem to want is
or (more compatible)