So we have done a number of tutorials here before that deal with javascript objects in some way, most notably Javascript Objects: A Useful Example, Using setInterval and setTimeout, and just this week Fun Object Syntax. Throughout all these you may have noticed that the this keyword can often have downright funky behavior. Today, we are going to take a look at exactly what this behavior is, and why it works this way.
First off, what is the this keyword? It is a keyword in javascript that is always supposed to point to the current object. You have probably seen it used (especially if you have read any of our javascript tutorials) to access/set properties or methods inside of an object. The this keyword is never null or undefined in javascript- it always defaults back to pointing at the global object (in browsers this would be the window object).
So the problems arise when our (the programmer's) conception of what the current object is does not mesh with the rules that the javascript interpreter follows. In that situation, we often end up with a this keyword pointing at the window object, instead of the object that we expect.
So lets take a look at some code:
{
var privateVal = "Private Val";
this.publicVal = "Public Val";
this.publicAlert = function()
{
alert("Public Call: " + this.publicVal);
alert("Public Call: " + privateVal);
}
var privateAlert = function()
{
alert("Private Call: " + this.publicVal);
alert("Private Call: " + privateVal);
}
this.Run = function()
{
this.publicAlert();
privateAlert();
}
}
var bar = new foo();
bar.Run();
Ok, so in this code we have two variables privateVal and publicVal, which are private and public variables respectively. We also have two functions privateAlert and publicAlert, again the first being a private function and the second being public. The public functions and variables have to be accessed using the this keyword - if you don't, there will be a variable undefined javascript error. So we finally call all these alerts - what is the output?
Public Call: Private Val
Private Call: undefined
Private Call: Private Val
Hmm, interesting - it looks like the privateAlert function does not know how to access this.publicVal. If we dig deeper, we find that the this keyword no longer refers to the foo object inside of privateAlert - it refers to the global window object. Well, I think we can all agree that that is no good.
Lets make the example even simpler, and see if that helps us understand anything more:
{
var privateVal = "Private Val";
this.publicVal = "Public Val";
var privateAlert = function(str)
{
alert(str + this.publicVal);
alert(str + privateVal);
}
this.Run = function()
{
privateAlert("Private Call: ");
this.publicAlert = privateAlert;
this.publicAlert("Public Call: ");
privateAlert = this.publicAlert;
privateAlert("Private Call: ");
this.publicAlert("Public Call: ");
}
}
var bar = new foo();
bar.Run();
This time, we just define privateAlert, not publicAlert. When the time comes to run, we run privateAlert, and set the variable this.publicAlert to the privateAlert function, and we call it. For good measure (just in case the act of assignment changed the function), we set privateAlert equal to publicAlert again, and call them again. This is the output:
Private Call: Private Val
Public Call: Public Val
Public Call: Private Val
Private Call: undefined
Private Call: Private Val
Public Call: Public Val
Public Call: Private Val
The same problem again! And this time we are calling the exact same function - it is just the way we are calling them. So it looks like when we call the function with the this keyword, this is properly defined inside the function. But when we don't, this ends up being a reference to the global (window) object, and not a reference to the current object (in this case the instance of foo).
Ok, now that we seem to have narrowed down the problem, I suppose it is time to take a look at the javascript (actually ECMAScript) spec and see if this is actually intended behavior. And it turns out that it actually is:
The ECMAScript 3 Language Specification (pdf)
"The caller provides the this value. If the this value provided by the caller is not an object (including the case where it is null), then the this value is the global object."
From Section 11.2.3 Function Calls:
The production "CallExpression : MemberExpression Arguments" is evaluated as follows:
1. Evaluate MemberExpression.
2. Evaluate Arguments, producing an internal list of argument values (section 11.2.4).
3. Call GetValue(Result(1)).
4. If Type(Result(3)) is not Object, throw a TypeError exception.
5. If Result(3) does not implement the internal [[Call]] method, throw a TypeError exception.
6. If Type(Result(1)) is Reference, Result(6) is GetBase(Result(1)). Otherwise, Result(6) is null.
7. If Result(6) is an activation object, Result(7) is null. Otherwise, Result(7) is the same as Result(6).
8. Call the [[Call]] method on Result(3), providing Result(7) as the this value and providing the list Result(2) as the argument values.
9. Return Result(8).
Wow, that is a mouthful. Reading language specs is never for the faint of heart. So, essentially, what that mass of text is trying to say is that if you have the following code:
As long as anObject actually is an object, the this inside of aFunction will be set to anObject. But if you call a function like:
What this get set to in this case is null, but it turns out that whenever this would end up being null, it gets set to the global object (the window).
So they actually designed the language to act this way. Which, while I guess it made sense at the time, does not make a whole lot of sense when I'm staring at the code I have above and wondering why it doesn't work. Hopefully, problems like this will not exist in the Javascript 2.0 spec.
But in the meantime we are sitting here in the Javascript 1.5 world. So what can we do to mitigate the problems cause by the this keyword? There is actually a way to program javascript objects so that we never run into this problem - never use the this keyword. I know, I know, that makes no sense - you are thinking that there are things that we can only do using the this keyword. Well, that is both true and false. Take a look at the following code:
{
var me = this;
var privateVal = "Private Val";
me.publicVal = "Public Val";
me.publicAlert = function()
{
alert("Public Call: " + me.publicVal);
alert("Public Call: " + privateVal);
}
var privateAlert = function()
{
alert("Private Call: " + me.publicVal);
alert("Private Call: " + privateVal);
}
me.Run = function()
{
me.publicAlert();
privateAlert();
}
}
var bar = new foo();
bar.Run();
See the first line of code inside of foo? I set the private variable me to the current value of this. At that point, the this keyword is pointing at the right object - the current instance of foo. And from that point onward, we never use the this keyword again - we only use the me variable. And since the value of me never changes, and everyone inside the object always has access to it, we get the output that we expect:
Public Call: Private Val
Private Call: Public Val
Private Call: Private Val
Well, I hope that cleared up any issues or questions that you might have about the this keyword in javascript, and why it so often ends up pointing at window. If anyone has any problems with the "me" variable technique, please post below - and of course other questions or comments are always welcome.
09/14/2007 - 09:24
Very cool reading. Good Job :)
03/11/2008 - 15:23
Thank you for posting the "me" technique. I have been bothered with the "this" problem for quite a while.
03/11/2008 - 20:18
you saved my soul, i have been trying this for long time, and didn't know what it is wrong.
03/16/2008 - 19:38
Thanks for posting the "me" trick! I was coming up with all sorts of hacks to get around it, including tracing down what "this" is pointing to at the current point when an exception occurs, and setting callback references on that object, but THIS is way simpler. Thanks again!!!
04/24/2008 - 20:23
very usefull article, very much helped, very much thank you, really :DDD
08/05/2008 - 04:51
hi,
the use of "this" keyword is not clear
11/14/2008 - 00:24
good keep it up
03/04/2009 - 19:17
var = this... simple and brilliant. Thank you.
03/31/2009 - 20:08
So cool, excellent work!!
04/10/2009 - 01:13
Wow man, thanks!
I come from a PHP background and when I was trying to implement classes in Javascript it just never worked out because of the "this" issue. It didn't make any sense to me... but this really cleared things up, thanks for sharing!
04/22/2009 - 13:57
I have to say, this is probably one of the most "relevant-to-what-I-was-doing" articles I have ever stumbled upon while searching for an answer to a problem. Very well written and easy to understand. Thank you so much for this fix, there are so few good articles on this subject.
05/15/2009 - 06:06
Thanks.So.Much !
Of dozens of documents I review for this issue, you're from very far the clearest and easiest to understand.
Whatever your gender is, this would make me want to marry you.
07/16/2009 - 22:21
It has been nearly two years since this was posted, and I can see that people are still replying with thanks.
Well... here is one more for you.
Thanks; Specifically for the "me" trick/technique.
08/20/2009 - 19:32
Here's a simple way of thinking. 'This' inside a function refers to future object instances of the function, usually created with operator new. So clearly 'this' of an inner function will never refer to an instance of an outer function.
The above should keep one out of trouble. But there are more complicated things you can do with 'this.' For example
function Q()
{
this.car = 'Honda';
alert(this.food); //'food' is the attribute of a
//future object and Q does not
//define it.
}
A = {food:'chili', q:Q}; //Create object A whose food
//attribute is 'chili' and
//whose q atribute is the
//function Q.
alert(A.car); //Displays 'undefined.'
A.q(); //Displays 'chili' but the call to Q also
//defines this.car.
alert(A.car); //Displays 'Honda.'
So in general, 'this' refers to the object to which the function is attached. Of course this was noted by the tutorial's author.
08/26/2009 - 20:06
Happened upon this by accident while I was looking for an answer to some other question. Answered a problem I was having months ago, to bad I didn't find this then, would have saved much hair pulling.
09/22/2009 - 14:59
Clear, lucid, unambiguous explanation of a screwed-up concept.
Sir, you totally rock. I bow my head before your awesomeness.
Thanks much.
09/24/2009 - 06:23
var wow={
init:function(){
alert("very good");comment();
},
comment:function(){
alert("Excellent try to follow me now");
}
}
wow.init();
09/24/2009 - 06:24
catch me there bye ya.
01/14/2010 - 09:45
One of the most important concepts to grasp in JavaScript is the use of the this keyword, which is used in object methods. The this keyword always points to the object that is calling a particular method, for example:
var oCar = new Object;
oCar.color = “red”;
oCar.showColor = function () {
alert(this.color); //outputs “red”
};
Here, the this keyword is used in the showColor() method of an object. In this context, this is equal to car, making this code functionality equivalent to the following:
var oCar = new Object;
oCar.color = “red”;
oCar.showColor = function () {
alert(oCar.color); //outputs “red”
};
So why use this? Because you can never be sure of the variable name a developer will use when instantiating an object. By using this, it is possible to reuse the same function in any number of different places. Consider the following example:
function showColor() {
alert(this.color);
}
var oCar1 = new Object;
oCar1.color = “red”;
oCar1.showColor = showColor;
var oCar2 = new Object;
oCar2.color = “blue”;
oCar2.showColor = showColor;
oCar1.showColor(); //outputs “red”
oCar2.showColor(); //outputs “blue”
In this code, the function showColor() is defined first (using this). Then, two objects (oCar1 and oCar2) are created, one with a color property set to “red”, and the other with a color property set to “blue”. Both objects are assigned a property called showColor that points to the original function named showColor() (note that no naming problem exists because one is a global function and the other is a property of an object). When calling showColor() on each object, the oCar1 outputs “red” whereas oCar2 outputs “blue”. This happens because the this keyword in the function is equal to car1 when oCar1.showColor() is called and equal to oCar2 when oCar2.showColor() is called.
Note that the this keyword must be used when referring to properties of an object. For instance, showColor() wouldn’t work if it were written like this:
function showColor() {
alert(color);
}
Whenever a variable is referenced without an object or this before it, JavaScript thinks that it is a local or global variable. This function then looks for a local or global variable named color, which it won’t find. The result? The function displays “null” in the alert.
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.