TechDoc: OOP in JavaScript

Posted on July 11, 2011

0


Introduction

From my point of view – using Java, ActionScript 3 and C# – JavaScript is not an Object Oriented Programming language.

You can not create explicit classes, explicitly define static variables and methods and the definition and instantiation of an Object is… …awkward.

Base article

  1. Javascript and OOP – by Tim Scarfe:
    1. Creating “Classes” and extending them with methods –  See here
  2. Object orienting programming in JavaScript – By Mike Koss.
    1. Super and sub-classes – Describing the object prototype-chain and how to use and “extend” the prototype of an object.  See here

Packages

What I found missing is the use of Class Packages and Package Chains. So I created my own library for that kind of stuff.

Functions, function body and function scope

One way to pretend OOP in JavaScript is by using a method or function as the constructor and “Class” body.

Like this:

// JavaScript "class" Cat
function cat(name) {
 // Returns an object that we can extend with methods
   this.name = name;
   // Methods are defined like this
   this.talk = function() {
	alert( this.name + " say meeow!" )
   }
} 

// Example code of use
cat1 = new cat("felix")
cat1.talk() //alerts "felix says meeow!"

Extending objects and creating Classes via prototyping

Prototyping is another way to extend a “Class”.

Instead of cramming the constructor method/body with other methods, we extend the base method by extending its prototype.

Unlike Java and C# there is no limit or limitation where and when you do this. As long as you are inside the same (root) scope as the method or object you extend.

// JavaScript "class" Cat
function cat(name) {
   // Returns an object that we can extend with methods
   this.name = name;
}
// Extend the base constructor with methods via the prototype
cat.prototype.talk=function(){
 // Due to the prototype we are in scope 
 // of the object made via the cat-method
   alert( this.name + " say meeow!" ) 
}

Super and sub-Classes

Each object returned by a function is of base type Object.

When you create a method, this method implies a new (derived) object which can be extended via its prototype as we did above.

Knowing this we can do the following with “cat”:

// Constructor function Cat( name )
{
    this.name=name;
} 
// Extending the prototype of cat by injecting Animal into the prototype Cat.prototype=new Animal();
// Making sure the constructor on the object is Cat Cat.prototype.constructor = Cat;

Creating packages

By default JavaScript uses a flat structure, without the Package Chains we know from OOP languages like Java or C#.

As I need this for a better structuring of the HotForestGreen JavaScript Library, I started the creation of a small OOP library for that today.

It extends the basic JavaScript Object with the method: getPackage( packageName);

As any object – including the JavaScript object delimiterd by <script></script> – is a JavaScript Object, the call to resolve a package looks like this:

// Get package reference - this is similar to "include" or "using"
var package = this.getPackage("peter.kaptein.package")

// Create the "Class" and constructor in the package
package.MyClass = function () {
	alert("MyMethod constructor")
}

// Define a method in our "Class"
package.MyClass.prototype.findMe = function () {
	alert("found me")
}

// Creating a new object with our nested Class
var object = new package.MyClass()
object.findMe(); // returns : "found me"

Result – still awkward, but better

Defining classes still feels very awkward, as I am used to state something like this:

// ActionScript package definition package package.chain.somepackage {
 // Class definition
     public class MyClass      {
            // Constructor and Class Body go here
    }
}

Using packages – which are retrieved and referred to using a simple method – however, makes it easier to store specific classes in specific place holders and create cleaner code.

It also prevents me from accidently overwriting other Classes which might do the same but nor really are the same.

Package naming and reference

Using meaningful names helps creating a second layer of neatness.

// Not really meaningful is the following
var bla = this.getPackage("bli.bla.bloo"); 
// which represent out super awesome Socket Stuff

Is less meaningful than:

// A clear naming 
var sockethandlerPackage = this.getPackage("network.sockets.handlers");
// So we know what we talk about

Reflection and lack of reflection

Unfortunately JavaScript does not support something like Strong Typing.

Everything we use is an generic object, and can change its type on run time.

This means that:

  1. Limited reflection – The editor you are using – and if it supports some sort of reflection – will only know what is in scope of a specific object due to its prototypes.
  2. No sanity checks on pre-compiling – Whatever methods and variables you call on an object: only when the application runs you will know if your code will break.

This means whatever we create based on a improvised OOP approach can only be tested on run time.

Assuring clean Package Chains

We want “some.nice.class.package.mypackage” to use the exact same Package Chain as “some.nice.class.package”.

To assure a clean package chain we use:

  1. Global lookup table with Class Packages – getPackage uses a global lookup table (which is a OOPackage object itself)
  2. Assure Package instead of “Create Package” – The Assure Package method calles “assurePackage” to check the existing Package Chains and assures we do not create multiple instances of parts of the same package chain.

					
Advertisements
Posted in: Uncategorized