Book Excerpt: Object-Oriented JavaScript
|
|
This chapter excerpt from
Microsoft AJAX Library Essentials by Cristian Darie, Bogdan
Brinzarea, is printed with permission from Packt
Publishing, Copyright 2007.
JavaScript Classes
Not only can JavaScript functions contain other functions, but they can also be
instantiated. This makes JavaScript functions a good candidate for implementing
the concept of a class from traditional object-oriented programming. This is
very helpful feature indeed, because JavaScript doesn't support the notion of a
class in the classic sense of the word. Functions can be instantiated using the
new operator, such as in this example:
var myHelloWorld = new ShowHelloWorld();
|
This line of code effectively creates an object named myHelloWorld, which
represents an instance of the ShowHelloWorld() function. When the object is
instantiated, the function code is executed, so creating the object has the
same effect as calling ShowHelloWorld() as in the previous examples.
Here are a few facts that will help you port your C# OOP knowledge into the
JavaScript world:
-
When a function is used as a class, its body code is considered to be the
constructor. In classic OOP, the constructor is a special method that doesn't
return anything, and that is called automatically when the object is created.
The same effect happens in JavaScript when creating an instance of the
function: its code executes. A C# constructor is equivalent to the code in the
JavaScript function—without including any inner functions (whose code doesn't
execute automatically).
-
In C# constructors can receive parameters, and also in JavaScript. If the code
in a function represents the "class constructor", the parameters received by
that function play the role of constructor parameters.
-
Class fields in JavaScript are created and referenced with the this keyword. In
a JavaScript function, this.myValue is a public member of the function (class),
while myValue is a local variable that can't be accessed through function
instances. Also, the local variable is destroyed after the function executes,
while class fi elds persist their value for the entire object lifetime.
-
Class methods that need to be accessible from outside the class need to be
referred to using this as well. Otherwise the inner function will be regarded
as a local function variable, rather than a "class" member.
We'll demonstrate these concepts by transforming the ShowHelloWorld() function
that you saw earlier into a "real" class. We will:
-
Change the name of the function from ShowHelloWorld() to HelloWorld().
-
Add a parameter named hour to the function's "constructor" so that we tell the
class the hour for which we need a greeting message, when instantiating it. If
this parameter is passed when creating objects of the class, we store it for
future use as a class fi eld. If this parameter is not specifi ed, the current
hour of the day should be stored instead.
-
The method DisplayGreeting() of the class should not support the hour parameter
any longer. Instead, it should display the greeting message depending on the
hour fi eld that was initialized by the constructor.
Once your new class is created, you use it just as you'd use a C# class. For
example, this is how you'd create a new class instance, and call its
DisplayGreeting() method:
// create class instance
var myHello = new HelloWorld();
// call method
myHello.DisplayGreeting();
A possible implementation of the HelloWorld class is the following:
// "Hello, World" class
function HelloWorld(hour)
{
// class "constructor" initializes this.hour field
if (hour)
{
// if the hour parameter has a value, store it as a class field
this.hour = hour;
}
else
{
// if the hour parameter doesn't exist, save the current hour
var date = new Date();
this.hour = date.getHours();
}
// display greeting
this.DisplayGreeting = function()
{
if (this.hour >= 22 || this.hour <= 5)
document.write("Goodnight, world!");
else
document.write("Hello, world!");
}
}
This code can be tested online at http://www.cristiandarie.ro/asp-ajax/
JavaScriptClass.html. The HelloWorld class is formed of the constructor code
that initializes the hour fi eld (this.hour), and of the DisplayGreeting()
method—this.DisplayGreeting(). Fans of the ternary operator can rewrite the
constructor using this shorter form, which also makes use of the object
detection feature that was discussed in Chapter 2:
// define and initialize this.hour
this.hour = (hour) ? hour : (new Date()).getHours();
Class Diagrams
JavaScript classes, just like C# or VB.NET classes, can be described visually
using class diagrams. There are standards such as UML (Unifi ed Modeling
Language), that can be used to model classes and the relationships between
them. In this book we'll show quite a few class diagrams using the notation
used by Visual Studio 2005. Using this notation, the HelloWorld class shown
earlier would be described as shown in Figure 3-2.
The diagrams to this book follow typical conventions for C# classes, which don't
translate to JavaScript exactly. For example, the diagram in Figure 3-2 says
that the HelloWorld class has an integer fi eld named hour. However, JavaScript
doesn't support specifying data types for variables or class fi elds. The data
type of the fi eld makes the diagram helpful in specifying the intended purpose
and type of the fi eld, but that type isn't used in the actual implementation
of the class.
The diagram also mentions the HelloWorld() constructor, which receives an
integer parameter. As you know, JavaScript doesn't support "real" constructors.
However, by reading the diagram you can tell that the HelloWorld() function
receives a parameter named hour, which is supposed to be an integer value.
Appendix A contains more details about the conventions used in class diagrams
throughout this book.
C# and JavaScript Classes
For the purpose of demonstrating a few more OOP-related concepts, we'll use
another class. Our new class is named Table, and it has two public fi elds
(rows, columns), and one method, getCellCount(). The getCellCount() method
should return the number of rows multiplied by the number of columns. The class
constructor should receive two parameters, used to initialize the rows and
columns fields. This class could be represented by the class diagram in Figure
3-3.
The C# version of this class would look like this:
public class Table
{
// public members
public int rows = 0;
public int columns = 0;
// constructor
public Table(int rows, int columns)
{
this.rows = rows;
this.columns = columns;
}
// method returns the number of cells
public int getCellCount()
{
return rows * columns;
}
}
Y ou'd instantiate and use the class like this:
Table t = new Table(3,5);
int cellCount = t.getCellCount();
The Table class can be easily implemented in JavaScript as shown in the
following code snippet, and it would resemble very much its C# version:
function Table (rows, columns)
{
// "constructor"
this.rows = rows;
this.columns = columns;
// getCellCount "method"
this.getCellCount = function()
{
return this.rows * this.columns;
};
}
After having declared the object, we can instantiate it by using the new
operator and use its properties and methods:
var t = new Table(3,5);
var cellCount = t.getCellCount();
There are a few subtle points you need to notice regarding the JavaScript
implementation of Table:
-
You don't declare public members explicitly. You simply need to reference them
using this, and assign some value to them; from that point on, they're both
declared and defi ned.
-
JavaScript allows you to implement most of the design specifi cations defi ned
in class diagrams, but the implementation can't refl ect the specifi cation as
accurately as a C# implementation can. For example, the line Table (int rows,
int columns) in the diagram in Figure 3-3 refers to the constructor of the
class. In JavaScript, as you know, classes as implemented using functions
neither have real constructors, nor support specifying data types for their
parameters.
-
When objects are created, each object has its own set of data—to maintain its
own state. However, C# and JavaScript are different in that in JavaScript
functions are fi rst-class objects. In C#, the "state" is made of the object's
fi elds. The object functionality, as defi ned by its methods, is the same for
all objects of the same type. For example, if you create many objects of the
type Table in C#, each object will have its own set of rows and columns, but
internally they all use the same copy of the getCellCount() method. In
JavaScript, however, functions are treated like any other variable. In other
words, creating a new Table object in JavaScript will result not only in
creating a new set of rows and columns values, but also in a new copy of the
getCellCount() method. Usually, you don't need (or want) this behavior.
-
The last mentioned problem is commonly referred to as a "memory leak", although
technically it's just ineffi cient JavaScript object design. When we design our
JavaScript "classes" as we do in typical OOP languages, we don't need each
class to create its own set of methods. It's only state (fi elds) that need to
be individual, and not methods' code. The good news is that JavaScript has a
neat trick that we can use to avoid replicating the inner function code for
each object we create: referencing external functions.
Referencing External Functions
Instead of defi ning member functions ("methods") inside the main function
("class") as shown earlier, you can make references to functions defi ned
outside your main function, like this:
function Table (rows, columns)
{
// "constructor"
this.rows = rows;
this.columns = columns;
// getCellCount "method"
this.getCellCount = getCellCount;
}
// returns the number of rows multiplied by the number of columns
function getCellCount()
{
return this.rows * this.columns;
}
Now, all your Table objects will share the same instance of getCellCount(),
which is what you will usually want.
Thinking of Objects as Associative Arrays
A key element in understanding JavaScript objects is understanding the notion of
associative arrays, which are nothing more than collections of (key, value)
pairs. As a .NET developer you have worked with associative arrays represented
by classes such as NameValueCollection, Hashtable, dictionaries, and others.
Unlike with normal arrays, where the key is numeric (as in bookNames[5]), the
key of an associative array is usually a string, or even other kinds of objects
that can represent themselves as strings. For example, take a look at the
following code snippet, where we retrieve the name of the book by specifying a
unique string value that identifi es that book:
// retrieve the name of the book
bookName = bookNames["ASP_AJAX"];
The concept is simple indeed. In this case, the key and the value of the
bookNames associative array are both strings. This associative array could then
be represented by a table like this:
Key
Value
ASP_AJAX Microsoft
AJAX Library Essentials
AJAX_PHP AJAX
and PHP: Building Responsive Web Applications
SEO_ASP Professional
Search Engine Optimization with ASP.NET
The table above can be represented in JavaScript, as an associative array, like
this:
// define a simple associative array
var bookNames =
{ "ASP_AJAX" : "Microsoft AJAX Library Essentials",
"AJAX_PHP" : "AJAX and PHP: Building Responsive Web Applications",
"SEO_ASP" : "Professional Search Engine Optimization with ASP.NET"
};
The key of an element doesn't have to be literal; it can even be specifi ed
through a variable:
// store the book ID in a variable
var bookId = "ASP_AJAX";
// display the name of the book
document.write("The name of " + bookId +
" is " + bookNames[bookId] + "<br />");
In JavaScript, however, the implementation of the associative array is more
powerful, in that it makes no restriction on the type of the value of the (key,
value) pair. The value can be a number, a string, a date, or even a function!
This fl exibility allows us to represent JavaScript objects as associative
arrays. For example, an instance of the Table class that we discussed earlier
can be represented like this:
// create Table object
var t =
{ rows : 3,
columns : 5,
getCellCount : function () { return this.rows * this.columns; }
};
// display object field values
document.writeln("Your table has " + t.rows + " rows" +
" and " + t.columns + " columns<br />");
// call object function
document.writeln("The table has " + t.getCellCount() +
" cells<br />");
This example, and the one presented earlier with book names, can be tested
online at http://www.cristiandarie.ro/asp-ajax/Associative.html, and the result
is presented in Figure 3-4.
Related Links
>Object
Oriented Programming Interview Questions
Concurrency with AOP
Concurrency is the system's ability to act with several requests simultaneously,
such a way that threads don't corrupt the state of objects when they gain
access at the same time............
Transparent caching with AOP
To get better results in terms of speed and resources used, it's suggested to
use a cache. We can store in it the results corresponding to the methods'
invocations as key-value pairs: method and arguments as key and return object
as value..............
Security with AOP
Security is one of the most important elements of an application. The word
"security" covers two concepts: Authentication is the verifi cation's process
of a principal's identity; a principal is typically a user. A principal in
order to be authenticated provides a credential that is the password.
Authorization, on the other hand, is the process of granting authorities, which
are usually roles, to an authenticated user...........
OOPS in .NET
What is the relation between Classes and Objects? Explain different properties
of Object Oriented Systems. What is difference between Association, Aggregation
and Inheritance relationships? Explain the features of an abstract class in
NET. Difference between abstract classes and interfaces Similarities and
difference between Class and structure in .NET Features of Static/Shared
classes. What is Operator Overloading in .NET?.............
What
are the advantages of OOP?
It presents a simple, clear and easy to maintain structure. It enhances program
modularity since each object exists independently............
What
encapsulation, inheritance, and polymorphism mean
In OOP's world everything revolves around objects and classes, and OOP languages
usually offer three specifi c features for manipulating them—encapsulation,
inheritance, and polymorphism........
|