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
thison a function by using the function’s.call()and.apply()methods.Long answer:
The
thisvariable on any function is similar to theargumentsvariable (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.lengthis not dependent on how or where we wrote the function, but on how we called the function. The same is true of thethisvariable (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
myFnisn’t a property of the object we want to call it on but the object follows the correct form formyFnto 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)(settingthisto the event’s target object). They do it in a more complex manner because of theircallbacksframework, 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.