MSDN May 2007: Create Advanced Web Applications With Object-Oriented Techniques
MSDN May 2007: Create Advanced Web Applications With Object-Oriented Techniques
MSDN May 2007: Create Advanced Web Applications With Object-Oriented Techniques
aspx
Contents
Create Advanced Web Applications With Object-Oriented Techniques....................1
JavaScript Objects Are Dictionaries......................................................................2
JavaScript Functions Are First Class......................................................................3
Constructor Functions but No Classes..................................................................7
Prototypes............................................................................................................9
Static Properties and Methods............................................................................13
Closures..............................................................................................................14
Simulating Private Properties.............................................................................16
Inheriting from Classes.......................................................................................17
Simulating Namespaces.....................................................................................19
Should You Code JavaScript This Way?...............................................................20
Putting It into Perspective..................................................................................21
1 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
a non-programmer can probably pick it up and write some useful scripts for a
homepage in a matter of hours.
Indeed, until recently, I’d always been able to get by with whatever little
JavaScript I knew, armed only with the MSDN® DHTML reference and my C++/C#
experience. It was only when I started working on real-world AJAX applications
that I realized how inadequate my JavaScript actually was. The complexity and
interactivity of this new generation of Web applications requires a totally different
approach to writing JavaScript code. These are serious JavaScript applications!
The way we’ve been writing our throwaway scripts simply doesn’t cut it anymore.
2 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
Note how similar it is to the C# 3.0 object initializers. Also, those of you familiar
with Python will recognize that the way we instantiate userObject in the second
and third snippets is exactly how we’d specify a dictionary in Python. The only
difference is that a JavaScript object/dictionary only accepts string keys, rather
than hashable objects like a Python dictionary would.
These examples also show how much more malleable JavaScript objects are than
C++ or C# objects. Property lastLoginTime doesn’t have to be declared
beforehand—if userObject doesn’t have a property by that name, it will simply be
added to userObject. This isn’t surprising if you remember that a JavaScript object
is a dictionary—after all, we add new keys (and their respective values) to
dictionaries all the time.
So, there we have object properties. How about object methods? Again, JavaScript
is different from C++/C#. To understand object methods, I first need to take a
closer look at JavaScript functions.
function func(x) {
alert(x);
}
func(“blah”);
This is how we usually define a function in JavaScript. But you can also define the
same function as follows, where you create an anonymous function object, and
assign it to variable func
3 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
};
func(“blah2”);
This shows that a function is really just an object that supports a function call
operation. That last way of defining a function using the Function constructor is
not commonly used, but it opens up interesting possibilities because, as you may
notice, the body of the function is just a String parameter to the Function
constructor. That means you can construct arbitrary functions at run time.
To demonstrate further that a function is an object, you can set or add properties
to a function, just like you would to any other JavaScript objects:
function sayHi(x) {
alert(“Hi, “ + x + “!”);
}
sayHi.text = “Hello World!”;
sayHi[“text2”] = “Hello World... again.”;
4 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
return func(num);
}
// displays 256
alert(operateOn(16, square));
With that in mind, adding methods to an object is as easy as choosing a name and
assigning a function to that name. So I define three methods in the object by
assigning anonymous functions to the respective method names:
var myDog = {
“name” : “Spot”,
“bark” : function() { alert(“Woof!”); },
“displayFullName” : function() {
alert(this.name + “ The Alpha Dog”);
},
“chaseMrPostman” : function() {
// implementation beyond the scope of this article
}
};
myDog.displayFullName();
myDog.bark(); // Woof!
The use of the "this" keyword inside the function displayFullName should be
familiar to the C++/C# developers among us—it refers to the object through
which the method is called ( developers who use Visual Basic should find it
familiar, too—it’s called "Me" in Visual Basic). So in the example above, the value
5 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
of "this" in the displayFullName is the myDog object. The value of "this" is not
static, though. Called through a different object, the value of "this" will also
change to point to that object as Figure 2 demonstrates.
Figure 2: "this" Changes as the Object Changes
function displayQuote() {
// the value of “this” will change; depends on
// which object it is called through
alert(this.memorableQuote);
}
var williamShakespeare = {
“memorableQuote”: “It is a wise father that knows his own child.”,
“sayIt” : displayQuote
};
var markTwain = {
“memorableQuote”: “Golf is a good walk spoiled.”,
“sayIt” : displayQuote
};
var oscarWilde = {
“memorableQuote”: “True friends stab you in the front.”
// we can call the function displayQuote
// as a method of oscarWilde without assigning it
// as oscarWilde’s method.
//”sayIt” : displayQuote
};
One thing to remember is never to call functions that contain "this" without an
6 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
owning object. If you do, you will be trampling over the global namespace,
because in that call, "this" will refer to the Global object, and that can really wreak
havoc in your application. For example, below is a script that changes the
behavior of JavaScript’s global function isNaN. Definitely not recommended!
So we’ve seen ways to create an object, complete with its properties and
methods. But if you notice all the snippets above, the properties and methods are
hardcoded within the object definition itself. What if you need more control over
the object creation? For example, you may need to calculate the values of the
object’s properties based on some parameters. Or you may need to initialize the
object’s properties to the values that you’ll only have at run time. Or you may
need to create more than one instance of the object, which is a very common
requirement.
you get back an object, which is an instance of the class Dog. But in JavaScript
there’s no class to begin with. This closest you can get to a class is by defining a
constructor function like this:
7 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
function DogConstructor(name) {
this.name = name;
this.respondTo = function(name) {
if(this.name == name) {
alert(“Woof”);
}
};
}
OK, so what’s happening here? Ignore the DogConstructor function definition for a
moment and examine this line:
What the "new" operator does is simple. First, it creates a new empty object.
Then, the function call that immediately follows is executed, with the new empty
object set as the value of "this" within that function. In other words, the line above
with the "new" operator can be thought of as similar to the two lines below:
As you can see in the body of DogConstructor, invoking this function initializes the
object to which the keyword “this” refers during that invocation. This way, you
have a way of creating a template for objects! Whenever you need to create a
similar object, you call “new” together with the constructor function, and you get
back a fully initialized object as a result. Sounds very similar to a class, doesn’t it?
In fact, usually in JavaScript the name of the constructor function is the name of
the class you’re simulating, so in the example above you can just name the
constructor function Dog:
8 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
alert(“Woof”);
}
};
}
In the Dog definition above, I defined an instance variable called name. Every
object that is created using Dog as its constructor function will have its own copy
of the instance variable name (which, as noted earlier, is just an entry into the
object’s dictionary). This is expected; after all, each object does need its own
copies of instance variables to carry its state. But if you look at the next line,
every instance of Dog also has its own copy of the respondTo method, which is a
waste; you only need one instance of respondTo to be shared among Dog
instances! You can work around the problem by taking the definition of respondTo
outside Dog, like this:
function respondTo() {
// respondTo definition
}
function Dog(name) {
this.name = name;
// attached this function as a method of the object
this.respondTo = respondTo;
}
This way, all instances of Dog (that is, all instances created with the constructor
function Dog) can share just one instance of the method respondTo. But as the
number of methods grow, this becomes harder and harder to maintain. You end
up with a lot of global functions in your codebase, and things only get worse as
you have more and more "classes," especially if their methods have similar
names. There’s a better way to achieve this using the prototype objects, which
are the topic of the next section.
Prototypes
The prototype object is a central concept in object-oriented programming with
JavaScript. The name comes from the idea that in JavaScript, an object is created
as a copy of an existing example (that is, a prototype) object. Any properties and
methods of this prototype object will appear as properties and methods of the
objects created from that prototype’s constructor. You can say that these objects
inherit their properties and methods from their prototype. When you create a new
Dog object like this
9 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
the object referenced by buddy inherits properties and methods from its
prototype, although it’s probably not obvious from just that one line where the
prototype comes from. The prototype of the object buddy comes from a property
of the constructor function (which, in this case, is the function Dog).
10 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
alert(spot.hasOwnProperty(“constructor”));
Every JavaScript object inherits a chain of prototypes, all of which terminate with
11 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
The way JavaScript resolves properties access and method calls dynamically has
12 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
some consequences:
• Changes made to a prototype object are immediately visible to the objects
that inherit from it, even after these objects are created.
• If you define a property/method X in an object, a property/method of the
same name will be hidden in that object’s prototype. For instance, you can
override Object.prototype’s toString method by defining a toString method
in Dog.prototype.
• Changes only go in one direction, from prototype to its derived objects, but
not vice versa.
Figure 7 illustrates these consequences. Figure 7 also shows how to solve the
problem of unnecessary method instances as encountered earlier. Instead of
having a separate instance of a function object for every object, you can make the
objects share the method by putting it inside the prototype. In this example, the
getBreed method is shared by rover and spot—until you override the toString
method in spot, anyway. After that, spot has its own version of the getBreed
method, but the rover object and subsequent objects created with new GreatDane
will still share that one instance of the getBreed method defined in the
GreatDane.prototype object.
function GreatDane() { }
GreatDane.prototype.getBreed = function() {
return “Great Dane”;
};
13 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
function DateTime() { }
// set static method now()
DateTime.now = function() {
return new Date();
};
alert(DateTime.now());
The syntax for calling the static methods in JavaScript is virtually identical to how
you’d do it in C#. This shouldn’t come as a surprise since the name of the
constructor function is effectively the name of the class. So you have classes, and
you have public properties/methods, and static properties/methods. What else do
you need? Private members, of course. But JavaScript doesn’t have native support
for private members (nor for protected, for that matter). All properties and
methods of an object are accessible to anyone. There is a way to have private
members in your class, but to do so you first need to understand closures.
Closures
I didn’t learn JavaScript of my own volition. I had to pick it up quickly because I
realized that I was ill-prepared to work on a real-world AJAX application without it.
At first, I felt like I had gone down a few levels in the programmer hierarchy.
(JavaScript! What would my C++ friends say?) But once I got over my initial
resistance, I realized that JavaScript was actually a powerful, expressive, and
compact language. It even boasts features that other, more popular languages
are only beginning to support.
One of JavaScript’s more advanced features is its support for closures, which C#
2.0 supports through its anonymous methods. A closure is a runtime phenomenon
that comes about when an inner function (or in C#, an inner anonymous method)
is bound to the local variables of its outer function. Obviously, it doesn’t make
much sense unless this inner function is somehow made accessible outside the
outer function. An example will make this clearer.
14 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
Let’s say you need to filter a sequence of numbers based on a simple criterion
that only numbers bigger than 100 can pass, while the rest are filtered out. You
can write a function like the one in Figure 8.
But now you want to create a different filtering criterion, let’s say this time only
numbers bigger than 300. You can do something like this:
And then maybe you need to filter numbers that are bigger than 50, 25, 10, 600,
and so on, but then, being the smart person you are, you realize that they’re all
the same predicate, "greater than." Only the number is different. So you can
factor the number out with a function like this
function makeGreaterThanPredicate(lowerBound) {
return function(numberToCheck) {
return (numberToCheck > lowerBound) ? true : false;
15 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
};
}
Closures may not seem like a big deal at first. But used properly, they open up
interesting new possibilities in the way you can translate your ideas into code.
One of the most interesting uses of closures in JavaScript is to simulate private
variables of a class.
The arguments name and age are local to the constructor function Person. The
16 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
moment Person returns, name and age are supposed to be gone forever.
However, they are captured by the four inner functions that are assigned as
methods of a Person instance, in effect making name and age live on, but only
accessible strictly through these four methods. So you can do this:
Private members that don’t get initialized in the constructor can be local variables
of the constructor function, like this:
Note that these private members are slightly different from what we’d expect
from private members in C#. In C#, the public methods of a class can access its
private members. But in JavaScript, the private members are accessible only
through methods that have these private members within their closures (these
methods are usually called privileged methods, since they are different from
ordinary public methods). So within Person’s public methods, you still have to
access a private member through its privileged accessors methods:
Person.prototype.somePublicMethod = function() {
// doesn’t work!
// alert(this.name);
// this one below works
alert(this.getName());
};
Douglas Crockford is widely known as the first person to discover (or perhaps
publish) the technique of using closures to simulate private members. His Web
site, javascript.crockford.com, contains a wealth of information on JavaScript—any
developer interested in JavaScript should check it out.
17 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
// class Pet
function Pet(name) {
this.getName = function() { return name; };
this.setName = function(newName) { name =
newName; };
}
Pet.prototype.toString = function() {
return “This pet’s name is: “ + this.getName();
};
// end of class Pet
Figure 9: Classes
Now what if you want to create a class Dog, which derives from Pet? As you can
see in Figure 9, Dog has an extra property, breed, and it overrides Pet’s toString
method (note that convention for JavaScript is to use camel casing for methods
and properties names, instead of Pascal casing as is recommended with C#).
18 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
Simulating Namespaces
In C++ and C#, namespaces are used to minimize the probability of name
19 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
One level of namespace may not be unique, so you can create nested
namespaces:
As you can imagine, typing those long nested namespaces can get tiresome
pretty fast. Fortunately, it’s easy for the users of your library to alias your
namespace into something shorter:
If you take a look at the source code of the Microsoft AJAX Library, you’ll see that
the library’s authors use a similar technique to implement namespaces (take a
20 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
In JavaScript, you’ve seen that objects inherit from objects (as opposed to classes
inheriting from classes). So it is possible that making a lot of classes using a static
inheritance hierarchy is not the JavaScript way. Maybe, as Douglas Crockford says
in his article "Prototypal Inheritance in JavaScript", the JavaScript way of
programming is to make prototype objects, and use the simple object function
below to make new objects, which inherit from that original object:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
Then, since objects in JavaScript are malleable, you can easily augment the object
after its creation with new fields and new methods as necessary.
This is all good, but it is undeniable that the majority of developers worldwide are
more familiar with class-based programming. Class-based programming is here to
stay, in fact. According to the upcoming edition 4 of ECMA-262 specification
(ECMA-262 is the official specification for JavaScript), JavaScript 2.0 will have true
classes. So JavaScript is moving towards being a class-based language. However,
it will probably take years for JavaScript 2.0 to reach widespread use. In the
meantime, it’s important to know the current JavaScript well enough to read and
write JavaScript code in both prototype-based style and class-based style.
21 of 22
http://msdn.microsoft.com/en-us/magazine/cc163419.aspx
quickly becoming one of the most useful tools in a .NET developer’s arsenal.
However, its prototypal nature may initially surprise developers who are more
used to languages such as C++, C#, or Visual Basic. I have found my JavaScript
journey a rewarding experience, although not entirely without frustration along
the way. If this article can help make your experience smoother, then I’m happy,
for that’s my goal.
22 of 22