Learning jQuery, Day 9: JavaScript's "this" variable
Today we won't actually be looking at jQuery, but about JavaScript itself. While jQuery is a terrific library, it's simply an abstraction of JavaScript methods for interacting with the Document Object Model (DOM). An abstraction is a wonderful thing, but it shouldn't be a substitute for understanding the base model -- JavaScript, in this case. Today, we'll look at one of the more confusing aspects of JavaScript: the "this" variable.
Readers familiar with ColdFusion's CFCs will understand that "this" refers to the referenced instance of a component. Take this code:
<cffunction name="process" access="public" output="false">
<cfargument name="id" required="true">
<cfif IsNumeric(id)>
<cfset this.processNumber(id)>
<cfelse>
<cfset this.processString(id)>
</cfif>
</cffunction>
<cffunction name="processNumber" access="private" output="false">
<cfargument name="id" required="true">
<!--- code here --->
</cffunction>
<cffunction name="processString" access="private" output="false">
<cfargument name="id" required="true">
<!--- code here --->
</cffunction>
</cfcomponent>
In the calls to "this.processNumber" and "this.processString", "this" refers to the current instance of the component, "Sample.cfc". That's true if you're used to languages like Java and C#, as well. JavaScript, though, is quite different.
Let's look at some JavaScript code from a file called "this.cfm":
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
function Composer(name, genre){
this.name = name;
this.genre = genre;
this.getName = function(){
return this.name;
};
};
$(document).ready(function(){
var beethoven = new Composer('Ludwig van Beethoven', 'Transitional');
alert(beethoven.getName());
});
</script>
</head>
<body>
</body>
</html>
Here, I've defined a function called "Composer" that defines a generic class for a composer. JavaScript functions are odd things to those of us used to class-based object oriented languages, but they have some similarities to ColdFusion functions. We can either create "stand-alone" functions or we can place them inside a CFC where they become methods of the component.
Here, we have a stand-alone function called "Composer" that will create a JavaScript object. It's helpful to think of JavaScript objects as properties and functions that are "attached" to a JavaScript object. Normally, "this" in the "this.getName" refers to the JavaScript "Composer" object. Another way of putting this is to say that "Composer" is the function context. That's the case here: if you run this code, you'll see that it will produce an alert: "Ludwig van Beethoven", since "this.name" refers to the "name" property of the Composer object.
But you can also instruct the function that it should subsitute a different object when referring to "this" -- that the function has a different function context. One way to do this is to explicitly call the function with the "call" method, as shown in "this2.cfm":
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
function Composer(name, genre){
this.name = name;
this.genre = genre;
this.getName = function(){
return this.name;
};
};
function Composition(name){
this.name = name;
};
$(document).ready(function(){
var beethoven = new Composer('Ludwig van Beethoven', 'Transitional');
var composition = new Composition('Symphony No. 5 in C Minor');
alert(beethoven.getName.call(composition));
});
</script>
</head>
<body>
</body>
</html>
Now, I've defined another function, "Composition", that also has a "name" property. And when I call "beethoven.getName.call(composition)", I'm telling JavaScript to use the object, "composition", as the basis for "this". Now, even though, "getName" is defined within the Composer object, the call to "getName" will not return "Ludwig van Beethoven" -- the "name" property of the Composer object -- but rather "Symphony No. 5 in C Minor" -- the "name" property of the Composition object.
Let's take one more example, "this3.cfm":
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
function getName(){
return this.name;
};
function Composer(name, genre){
this.name = name;
this.genre = genre;
this.getName = function(){
return this.name;
};
};
function Composition(name){
this.name = name;
};
$(document).ready(function(){
var beethoven = new Composer('Ludwig van Beethoven', 'Transitional');
var composition = new Composition('Symphony No. 5 in C Minor');
alert(getName());
});
</script>
</head>
<body>
</body>
</html>
Now, I have a stand-alone function called "getName" in addition to the function within the Composer function. So, what will be displayed when I call "getName()"? Nothing. In the case of stand-alone functions, "this" refers to the window object, and that window object's "name" property is blank.
But, I can alter the function context for the stand-alone function, "getName" with this code:
The function context is now the object, "beethoven", whose name property is "Ludwig van Beethoven". You can alter the code to set the event context to the "composition" object and it will display "Symphony No. 5 in C Minor".
Now, you may be asking, "Why would I want to change the function context? That's a very good question -- and I'm going to have to ask your indulgence in not answering that -- at least not in this post. I promise, though, that in future posts, we'll see that changing the meaning of "this" can be a very powerful feature of JavaScript.

