This “this” is Your This

Tuesday, October 12, 2010 | 2:04 PM

In a past blog post, we talked about how Closure Compiler makes it easier to share common JavaScript by ensuring that everybody declares what variables they own.

Global variable uniqueness is something that we added checks for fairly early on. Some restrictions are less obvious. In this blog post we’ll talk about the this keyword.

Suppose Nathan wants to outsource hot dog eating contests, so that we don’t need an instance of Nathan to run one. To do so, he takes runHotDogContest and unpackHotDogs off the prototype, and makes them into static methods. The code now looks like this:

Nathan.runHotDogContest = function(player, boxes) {
for (var i = 0; i < boxes.length; i++) {
player.eatHotDogs(this.unpackHotDogs(boxes[i]));
}
};


I want to run 2 hot dog contests, so naturally, I write:

var run = Nathan.runHotDogContest;
run(joey, crateA);
run(kobayashi, crateB);


The code fails with an error that unpackHotDogs is not defined on this. The reason is subtle. To the person writing Nathan.runHotDogContest, this and Nathan seem like interchangeable variables. And as long as you’re testing them by invoking them as:

Nathan.runHotDogContest(joey, crateA);
Nathan.runHotDogContest(kobayashi, crateB);


then they will be interchangeable.

In fact, this is a secret argument to the function. It’s much like any other function argument, except that it appears on the left side of the function call instead of on the right side. So Nathan.runHotDogContest(...) passes Nathan as the this argument, and run(...) passes null as the this argument (which JavaScript helpfully coerces to window).

To make Closure Library usable, the library authors and the library users need to agree on what the arguments to a function mean. This includes secret arguments like this. So we’ve agreed that only constructors and prototype methods may use this, and the this argument must be an instanceof the relevant constructor. Closure Compiler enforces this in --warning_level VERBOSE, and will often emit a warning if it sees this used in a dangerous place.

If you’re writing a function that expects an unusual this context, you can explicitly document it with the @this annotation, and the warning will go away.

Good luck with all of this!

2 comments:

Alfonso said...

Nick,

Having just discovered closure tools via a module in the fantastic play framework, I wonder, what does the future hold for the library? (since the last post on is October 2010)

Thanks

Allan

Eric said...

Very interesting. JavaScript has a lot of quirks with the "this" keyword, and this is one of them I didn't know about until now.

Thanks for sharing and your work on the library.