A.I on the 1s and 0s

Alnur Ismail is a PM for Microsoft's XAML

June 2009 - Posts

Part 2 – Object Oriented JavaScript (MS AJAX)

I recently gave a presentation on Object Oriented JavaScript (OOJ) and received some good feedback so the next few posts will be a more verbose version of that presentation.

AGENDA

Part 1 – JavaScript Review
Part 2 – How
Part 3 – Why Use OOJ?
Part 4 – Example

Part 2 – How

Custom Objects

Using what was covered in Part 1 we can start to create our own custom objects. First we need to write a constructor by using a function:

function Team(name, league) {
this._name = name;
this._league = league;
}
 
To create an instance of a Team we can use the function together with the new operator to create a new object and invoke the constructor:
 
var t = new Team('Arsenal', 'EPL');

The Prototype Object

Briefly mentioned in Part 1 the prototype object defines the template of an object. It is similar to a class in C# because it holds all the properties that will be inherited by any instance. However, there is one major difference between an instance of an object in C# that inherits from a class, and an object in JS that inherits from the prototype – all objects and arrays added to the prototype are shared between all instances. Consequently, it is a best practice to store all the members in the constructor and all methods in the prototype. If you are interested in learning more about the prototype object you can [Kool-Aid alert] Bing it.

The Microsoft AJAX Library

If you’re using ASP .NET to build AJAX infused applications you’ve probably heard about and used the AJAX Control Toolkit. Maybe you’ve wondered how these MS guys create such powerful controls? Well, if you take a look at the source you’ll see that they are are using the MS AJAX library to OOJ (it’s a verb and a noun). So why the hype? Because the MS AJAX library lets you easily simulate OO constructs such as: classes, properties, interfaces and enumerations that are not currently supported in JavaScript. Let’s take a look at how to use the library…

Classes

To make the above Team object a class all we need to add is one line of code after the constructor has been declared:

function Team(name, league) {
this._name = name;
this._league = league;
}
Team.prototype = {
getRoster : function() {
//..
}
}
//code responsible for making the constructor behave as a class
Team.registerClass('Team');

The registerClass in the above example is responsible for making the constructor behave as a class but it can do more that just that. It is responsible for:
  1. Registering the type name (ex. Team) in the constructor so you can access it at runtime (normally you declare a class by assigning it to a namespace variable so the class becomes an anonymous function which I talked about in Part 1. You always want to use the fully qualified name of the class otherwise you loose the ability to access it.)
  2. Resolving an inheritance relationship if a base class is provided
  3. Letting you specify one or many interfaces

Here is an example of how to use registerClass to do those three things :

FIFA.League.EPL.Team.registerClass('FIFA.League.EPL.Team'
, FIFA.League.Team
, FIFA.League.ITeam);
 
This translate to:
 
FullyQualifiedClassName.registerClass('FullyQualifiedClassName'
, BaseClass
, Interface);

Properties
 
To expose properties (aka getters and setters in C#) in a JavaScript object add two functions to the Team prototype object like so:
 
Team.prototype = {
//...
getName() : function () {return this._name;},
setName(): function (value) { this._name = value;}
}

By declaring member variables using this pattern there is no way to set private scope so although you could just directly get/set the variables you would loose the ability to perform any required logic. (Note: there is a way to make a variable private in JS using closures but it won’t work following the MS AJAX best practices. I’ll write another post about that because sometimes I’ve found MS AJAX to be overkill when you need a simple standalone object.)

Namespaces

From the registerClass example above the Team class is being accessed through a series of namespaces. To create a namespace use:

Type.registerNamespace('FIFA');
 
For a nested namespace use:
 
Type.registerNamespace('FIFA.League');

Inheritance

Remember that to accomplish inheritance in JS we need to inherit from the prototype object. We do this by using the registerClass method that was shown above. But, we also need a way to:

  1. Call the base constructor
  2. Pass parameters to the base constructor
  3. Override methods inherited from the base
  4. Call base methods

MS AJAX makes these four tasks fairly simple. To call the base class constructor and to pass it some parameters use the initializeBase(…) method that takes two parameters. The first parameter is the child class that is inheriting and the second is an array of parameters we need to pass. To override a method replace the function with your own just like in C#, and calling a base method is as easy as calling the callBaseMethod(…) method which takes three parameters: the current instance, the method name to call, and an array of method parameters.

Here is an example:

Type.registerNamespace('FIFA');


//Player Base Class
FIFA.Player = function (name, age) {
this._name = name;
this._age = age;
}
FIFA.Player.prototype = {
strategy : function() {
//Perform player logic
}
}
FIFA.Player.registerClass('FIFA.Player');


//Defender Derived Class
FIFA.Defender = function(name, age) {
FIFA.Defender.initializeBase(this, [name, age]);
//Perform additional logic
}
FIFA.Defender.prototype = {
strategy : function() {
FIFA.Defender.callBaseMethod(this, 'strategy');
//Perform additional logic
}
}
FIFA.Defender.registerClass('FIFA.Defender', FIFA.Player);



Interfaces & Enumerations

Interfaces and enumerations follow a similar pattern. MS AJAX uses functions to implement both but we need to stop a user from calling the constructor to create instances of them, and also stop a user from calling the methods of the interface. This can be achieved by using Error.notImplemented() in the function body so the actions error out “by design”. We define the functions of the interface or the names of the enumeration in the prototype, and after the declaration call either registerInterface or registerEnum.

FIFA.Leagues.Teams.ITeam.registerInterface('FIFA.Leagues.Teams.ITeam');
FIFA.Results.registerEnum('FIFA.Results');

In the next and final part of this series I’ll talk about why you should use OOJ and also provide a comprehensive example that ties everything together.

Part 1 - Object Oriented JavaScript (Using MS AJAX)

I recently gave a presentation on Object Oriented JavaScript (OOJ) and received some good feedback so the next few posts will be a more verbose version of that presentation.

AGENDA

Part 1 – JavaScript Review
Part 2 – How
Part 3 – Why Use OOJ?
Part 4 – Example

 Part 1 – JavaScript Review

Before we get to the good stuff I want to review the basic fundamentals of JavaScript which we will build on in Part 2.

JavaScript Objects

Believe it or not, JavaScript is a true object oriented language. However, objects in JavaScript are different than objects in C# because JavaScript doesn’t have classes which means you can’t create an instance of a class like you would in C#. Instead you need to manipulate the native Prototype object which can be though of as a template. The Prototype object will be discussed in detail a little later. So what is a JavaScript object? Put simply, a JavaScript object is no more than a collection of name/value pairs.

You can create a JavaScript object by using:  

var person = new Object();

JavaScript Properties

JavaScript properties can be added at any time unlike C# where all properties are defined in the class. Properties can be added by using:

person.name = 'Alnur Ismail';

Or, to show that JS objects are really no more than a collection of name/value pairs we can use the indexed notation.
 
person['gender'] = male;

JavaScript Functions

In JS functions are first class objects. This is a fancy way of saying they can do everything regular objects can do such as being: instantiated, returned by other functions, stored as elements of arrays and assigned to variables. The latter, also referred to as an anonymous function, is important to understand when it comes to OOJ because when a function is assigned to a variable there is no way of getting to that function without knowing the property name. More on this later.

 

That’s all you really need to know about JavaScript to take advantage of OOJ. I’ll discuss the “how” of OOJ in Part 2.

More Posts