JavaScript: this
JavaScript is a language steeped in juxtaposition. It was made to “look like Java,” yet is dynamic and classless. From this origin, we get the new
operator and the this
keyword. You are probably used to this
referring to the current instance of a class, so what could it mean in a language without classes?
In JavaScript, this
refers to the object off of which a function is referenced when it is invoked (unless it is invoked via call
or apply
). What this means is that this
is not bound to your function, and can change depending on how your function is invoked. It also means that this
changes when declaring a function inside another function (i.e. each function has its own this
), such as when writing a callback. Let's see some of this in action:
var obj = { count: 0, increment: function () { this.count += 1; }, logAfterTimeout = function () { setTimeout(function () { console.log(this.count); }, 1); } }; obj.increment(); console.log(obj.count); // 1 var increment = obj.increment; window.count = 'global count value: '; increment(); console.log(obj.count); // 1 console.log(window.count); // global count value: 1 var newObj = {count:50}; increment.call(newObj); console.log(newObj.count); // 51 obj.logAfterTimeout();// global count value: 1 obj.logAfterTimeout = function () { var proxiedFunction = $.proxy(function () { console.log(this.count); }, this); setTimeout(proxiedFunction, 1); }; obj.logAfterTimeout(); // 1 obj.logAfterTimeout = function () { var that = this; setTimeout(function () { console.log(that.count); }, 1); }; obj.logAfterTimeout(); // 1
The last couple of examples here demonstrate some methods for making sure you get the values you expect. The first time logAfterTimeout
is redefined, we use jQuery.proxy
to create a new function which has its this
permanently set to the passed in value (in this case, the current this
). The second time logAfterTimeout
is redefined, we save the value of this
in a variable (named that
in this case, also often named self
) and use the new variable in place of this
.
Now, all of this is to clarify what’s going on when you use this
. However, it’s pretty easy to avoid using this
altogether in your code (especially in the way I’ve demonstrated above). Instead of using this.count
all over the place, it would have been much easier if I’d made count
a variable instead of a property, and then I wouldn’t have to use this
to refer to it.
var obj = (function () { var count = 0; return { increment: function () { count += 1; }, logAfterTimeout = function () { setTimeout(function () { console.log(count); }, 1); }, getCount: function () { return count; } }; }());
If you’re writing your code in this way, the main place you’ll run into issues with this
is when handling DOM events (where this
is the element on which the event occurred). In that case, just be careful when using a callback within that event handler, that you’re not expecting this
to still refer to the element (and use proxy
or that
/self
if you need to refer to it).
Finally, as demonstrated in the example, you can use call
or apply
on a function to set its this
value. This isn’t often needed, but you may also want to know that you can use apply
to pass in an array of arguments to a function (e.g. console.log.apply(console, [1, 2, 3, 4])
).