CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }

Pragmatic OOP in JavaScript

JavaScript is the only language a web browser speaks; it is a given fact. It's not a matter of choice if you are going to work with it, whenever you build a browser app it is there. All script code might be hidden to you but there is no ASP.NET, let alone Atlas (AJAX) without JavaScript. Recently I've been doing a project which involved loads and loads of JavaScript. Being a C# addict myself I had to get used to it but quite soon I found it had more power than I believed at first. The first thing I wanted to know about my new programming environment is how it supports OOP. When browsing for information on JavaScript and OOP the problem seems to be that two disciplines have such a different background. The majority of JS is produced by web-designers who have to write some code to get their site working. The majority of OOP information is provided by "real" programmers who look down on JS. And there are people like Douglas Crockford to whom JavaScript is the language where almost every way of programming meets. I don't share his enthusiasm but his site is a must read and did provide me the best basis for workable patterns. As promised here is my, C# based, way of OOP in JavaScript.

Getting started with JavaScript

Getting started is no big deal. At first sight you just start typing ahead pretending to write in C#. But there is no compiler or unit testing to validate your work; not until the code is interpreted at run time. As you can do horrible things in JavaScript it does take a lot of discipline to write good code. Also because the language itself is not as strict as C#. The following snippet of code will run

function CheckId()
{
    if (text1.value != "")
    {
        Id = ++text1.value;
    }
    else
    {
        id = -1;
    }
    return id;
}

An undeclared variables is created on the fly with global visibility. In this case two, Id and id, are introduced. All script code on the webpage will see an Id a an id variable (the different casing is a typing error). As JavaScript is case-sensitive these are two distinct members. Both will keep their value over calls to the function. But this id does not make much sense outside of the function.

You limit the visibility of a member using the var keyword. This code does the same without any of the side effects.

function CheckId2()
{
    var id = -1;
    if (text1.value != "")
        id = ++text1.value;
    return id;
}

Note that variables and functions in JS do not have a type. The value of the function result or the variable's values is formed by the context. Which can lead to confusing things. These three expressions are all true

1 + 2 == 3;
1 + '2' == '12';
1 + '2' ==  12;

The last one looks funny at first sight. But it makes sense when a ToString() is applied first to every member of the expression.

Objects in JavaScript

In C# an object is described by the class it's instantiated from. The class is the type of the object. We just saw that the JavaScript language does not have types. Objects in JS are created by a constructor function. An object in JS is a dynamic collection of variables and functions. All methods in JavaScript are functions, a procedure is in JS a function without a return statement. The constructor function below creates a new object with a Name and a Counter member.

function MyObject()
{
    this.Name = 'A Javascript object';
    this.Counter = 0;
}

The this keyword marks the members as public accessible. You instantiate an object using the new keyword.

<script>
    var myObj = new MyObject();
    function CountOnMyObject()
    {
        text1.value = myObj.Name + ' ' + (++myObj.Counter);
    }
</script>
<input type="text" size=90 id ="text1" />
<input type="button" value = "Debug" onclick="CountOnMyObject()">
 

When the page is loaded the new object is created. On every click of the button the count is raised and the object returns it's name and count. Here we have the base of object orientation, the possibility to bundle data and functionality at work.

There are several ways to add methods to the objects. What you will find most is a declaration which adds a function to the so called prototype of the object. These functions can access the other members of the object..

function MyObject()
{
    this.Name = 'A Javascript object';
    this.Counter = 0;
}

function MyObject.prototype.DoubleCount()
{
    return this.Counter * 2;
}

The DoubleCount() function returns twice the current value of the Counter member.

As said, JavaScript objects are a dynamic collection of members. These members can be variables or functions. Any piece of code can add a member on the fly. This can be done inside an existing member of the object.

function MyObject.prototype.DoubleCount()
{
    this.OnTheFlyMember = 'Set';
    return this.Counter * 2;
}

The result is that myObj.OnTheFlyMember is undefined until the first time myObj.DoubleCount() is called.

But it can even get greasier than that. Also a snippet of script consuming the object can add a member on the fly

<script>
    var myObj = new MyObject();
    function AddMemberToMyObject()
    {
        myObj.MemberFromScript = 'Hello from a snippet of script';
    }
</script>
 

We will see later the not just member variables but also member functions can be added or altered. To some people this dynamic nature of JavaScript is a bliss which opens the doors to great ways of programming. I'm not sure about that, there are other languages in case I would dive into that. Me and other mortals just need plain simple, maintainable and easy to understand code. Object orientation is a step towards that but the OO we have seen so far is no more than a bundling of variables and functions with a public visibility.

<Update>Part 2 further discusses prototype</update> 

What makes objects far easier to work with is encapsulation. Not just hiding the implementation of the method but also hiding all internal data inside the object and all helper methods without any relevance to the object's consumer. An object should only expose those members which are of relevance to the consumer. This is done in JavaScript using a slightly different syntax.

Now all functions are defined in the constructor function.

function MyObject()
{
    var name = 'A Javascript object';
    var counter = 0;

    this.Count = function()
    {
        counter++;
    }

    this.Name = function()
    {
        return name + ' with a count of ' + counter;
    }
}

Using the var keyword the name and counter's visibility are limited to the constructor function. As the exposed members this.Count and this.Name are also declared inside the constructor function they can reach the private vars. They are named privileged members. The members declared on the prototype are named public. To the script consuming the objects there is no difference except when it comes to working with the prototype, something we will meet when taking a look at inheritance. The object exposes public and privileged methods and encapsulates the private vars.

Also a helper method can be a private member. It is used by the object's members but is not visible by the object's consumer.

function MyObject()
{
    var name = 'A Javascript object';
    var counter = 0;

    function capFirst(aString)
    {
        var str1 = aString.substr(0,1);
        var str2 = aString.substr(1);
        return str1.toUpperCase() + str2.toLowerCase();
    }

    this.Count = function()
    {
        counter++;
    }

    this.Name = function()
    {
        return capFirst(name + ' with a count of ' + counter);
    }

    this.AnotherName = function(anotherString)
    {
        return name + ' ' + capFirst(anotherString);
    }

}

Now we have objects which can hide data and implementation and expose just that what is of interest to the consumer. Just like the .net object you're used to.

Methods, overloads and properties

In a language like C# you have overloads, that is multiple versions of a method each with a distinct parameter list. There is no such thing in JavaScript. The function with a matching name is called passing it all parameters. Even when the parameters are not specified in the function declaration they are available in the function's implementation via the arguments keyword. This AnotherName method declares only 1 parameter.

function MyObject()
{
    this.AnotherName = function(anotherString)
    {
        return arguments.length;
    }
}

When you use it with a longer parameter list, like this:

text1.value =myObj.AnotherName(text2.value, 'Boe', 'Blub', 9);

the AnotherName method will still be hit and it will return 4 . You can use something like overloads in JavaScript but all implementation has to be done within one method. It has to inspect the number and content of the arguments actually passed and act accordingly.

To have the kind of object you're used to, where methods can reach private data, requires privileged members. What the JavaScript syntax in such a declaration actually does is assign a function variable to a member of the object

this.MemberName = function(params)

This dynamic way JS mixes code and data can hit back when you look at properties. The constructor function below initiates a property Name and a privileged method AnotherName.

function MyObject()
{
    this.Name = 'A Javascript object';

    this.AnotherName = function(anotherString)
    {
        return 'Another ' + anotherString;
    }
}

The consumer can read and set the Name property and call the AnotherName method.

text1.value = myObj.Name;
text2.value = myObj.AnotherName(text2.value);
text3.value = myObj.AnotherName;

The third statement is also valid. The object has besides the method AnotherName() also a  property AnotherName (without parenthesis). The property will return the implementation of the AnotherName method. The first time you meet this, for instance when you forget the parenthesis in a method call it will make you scratch your head. The bad thing is that you can also set this method property from code. Needless to say that this is the way to have your carefully crafted code wrecked by consuming code. Or altered, which is a next subject.

Static members

A static member is a member which is available without first creating an object instance. JavaScript does have static members. They are declared outside of the constructor function.

function MyObject()
{
    this.Name = 'A Javascript object';
}

MyObject.MyStaticProp = 'This is a static property';

function MyObject.MyStaticFunction()
{
    return 'This is a static function';
}

You use them in your code by using the constructor function's name as a prefix.

text2.value = MyObject.MyStaticFunction();

The usability of static members is limited as they cannot be used by the privileged members. But they are a nice way to organize a bunch of related functions into a class.

Inheritance

Inheritance is the weak spot in JavaScript's OOP implementation. The language itself does not include the idea. Scattered over the web you will find a wide variety of hacks to implement it. Harry Fuecks tries to give an overview and does provide an, at first sight, elegant solution himself. The main problem with all the implementations, including his, is that they work with the prototype and thus only work for public members. The big problem we just saw with public members is that they cannot work with encapsulated private members. The way to keep your objects clean is using privileged members, that was having all code in the constructor function. The implementations found on the web don't work with these privileged members.

A reason for inheriting from a base class is polymorphism, where you pass an object of a derived class to code expecting an object of the base class. As JavaScript just tries at runtime if the object has a member with a matching name, polymorphism will always work as intended. Another reason for inheritance is changing the behavior by overriding members. We have seen that you can add or replace any member of a JavaScript object on the fly. Instead of inheriting you can aggregate an object, using a base class to implement things. Take these creatures

function Animal(named)
{
    var name = named ? named : 'Unknown';
    this.Name = function()
    {
        return name;
    }

    this.MakeSound = function()
    {
        return 'That\'s the ' + name + ' sound';
    }
}

function Cat()
{
    var base = new Animal('Cat');

    this.Name = base.Name;
    this.MakeSound = function()
    {
        alert('Mew');
        return base.MakeSound();
    }
}

The Animal constructor function provides an object with basic functionality. The Cat constructor creates an Animal object, passing in a value for the name. The Cat constructor exposes the animal's Name function and provides an own implementation of the MakeSound function which augments the base implementation.

<Update>Part2 discusses a variation</update> 

Most hacks on the web are able to publish all public methods in one go using the prototype. I have to explicitly re-publish every privileged member. But the members of my object can keep working with shared private var's; provided the members are in the same class, the Cat constructor cannot see the Animal name var. I need some extra lines but this is a price I'm quite willing to pay for a better encapsulation.

Conclusion

The four tenants of OOP programming are abstraction, encapsulation, inheritance and polymorphism. Judging JavaScript on each of them

  • Abstraction is met. The object consumer only sees published members, not the implementation.
  • Encapsulation is met. Not only the code but also private data can be hidden from the object consumer
  • Inheritance is not met, but thanks to JavaScript objects being dynamic a simple and pragmatic work-around is possible
  • Polymorphism is in the core of the language.

The main point of JavaScript to me is being able to work with it in a pragmatic manner and have simple well structured code. Which is possible as long as I restrict myself.

 



Comments

Jeremy D. Miller said:

Peter,

Maybe I'm not reading close enough, but why is it that you don't think JavaScript supports inheritance?  You can do this:

function Animal(named)

{

   var name = named ? named : 'Unknown';

   this.Name = function()

   {

       return name;

   }

   this.MakeSound = function()

   {

       return 'That\'s the ' + name + ' sound';

   }

}

function Cat()

{

   var base = new Animal('Cat');

   //base.Name = base.Name; <-- unnecessary

   base.MakeSound2 = base.MakeSound; // could probably do this another way

   // override away

   base.MakeSound = function()

   {

       alert('Mew');

       return this.MakeSound2();

   }

   return base;

}

Yes, calling base.Anything() is clumsy, but how often do you really need that?

You might also point out that you can take any DOM object, i.e. a Textbox, dropdown, span, div, whatever and tack on additional properties and methods at will.  I doubt that most people realize that.

# October 24, 2006 5:16 PM

pvanooijen said:

Jeremy,

Nice, that works as well. Even better because now I don't have to republish.

It's the constructor returning another object (an altered base), not this.

return base;

I'm not sure if I would call it inheritance. It's in all cases closer than my approach.

Indeed, every DOM object can be given the treatment i've lined out. Good to mention.

# October 25, 2006 3:00 AM

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# October 25, 2006 6:56 AM

Sergio Pereira said:

Great post. I salude you for putting this together and helping lots of developers that are starting to go through the same challenges you experienced.

Inheritance: Now try creating 2,000 Cat objects and see all those method definitions being multiplied in memory. To mimic inheritance, you should really try your best to work with the 'prototype' property of your class. That's what the prototype.js library and many others do. Dean Edwards has some interesting works in this subject, most notably the Base.js implementation: http://dean.edwards.name/weblog/2006/03/base/

# October 25, 2006 7:24 AM

Michael Urquiola said:

I've been doing OOP with JavaScript for a long time.  A few tips.

I like this way of encapsulating functions in objects.

function MyObj(){

 this.myFunc = _myFunc;

 function _myFunc(){

 }

}

Often times you need a pointer to the object you're a part of within a function, in cases where your called from say an event handler.

function MyObj(){

 var curObj = this; //set curObj to MyObj on creation

 this.myProp = true;

 this.EventHandler= _EventHandler;

 function _EventHandler(){

   //"this" when called from an event is the object raising the event "textbox"

   //use curObj to get at properties and functions in the MyObj context

    if (curObj.myProp) //do something

    this.style.backgroundcolor = "blue" //change the background color of the text box

 }

}

obj = new MyObj()

textbox.onclick = obj.EventHandler;

# October 25, 2006 10:06 AM

pvanooijen said:

thanks everybody for the idea's. A way to fake inheritance is a good subject to dive deeper into. I'll come back on that.

# October 26, 2006 3:27 AM

Bob.Yexley.Net said:

Peter Van Ooijen wrote a fantastic article on how to apply object-oriented design concepts to JavaScript

# October 26, 2006 2:56 PM

Pat Allan said:

Hi Peter

I'm not certain, but my understanding of the difference between declaring methods of objects via Class.prototype.methodName and function Class() { function methodName(); } is that the former is much better for memory usage in the browser.

Keep in mind I'm not certain about this, but I *think* when instances of the object are created, with the Class.prototype it doesn't store a copy of every function in memory for each instance, whereas the other way of doing things means every instance keeps track of it's own copy of the methods - so having a lot of objects uses up a *lot* more memory.

That said, I'm not sure. Thanks for the clear discussion around this though :)

# October 27, 2006 7:46 PM

Pat Allan said:

Ah, I missed the details of Sergio's comment. Seems mine was unnecessary.

# October 27, 2006 7:47 PM

Creative Minds said:

OOP in JavaScript

# October 30, 2006 6:58 AM

Peter's Gekko said:

My recent post on object orientation in JavaScript has resulted in some quite interesting comments. Good

# October 31, 2006 7:38 AM

Mitesh Shah said:

Hey just wanted to ask how can i retrieve my C# object using javascript.

i.e pass a C# object to javascript

# December 15, 2006 2:33 AM

pvanooijen said:

Expose the functionality using COM works, as JS knows how to work with COM objects. It is also possible to directly addres an embedded object in your browser. The public properties and methods can be addressed.

# December 15, 2006 2:47 AM

vashisht said:

Hi

Can u please guide me like how to remove the object item in java scaript.

var hash=new Object();

function getValue()

{

hash['a']=7;

hash['bj']=3;

alert(hash['bj']);

       /* i did thsi by assigning the null value*/

hash['b']=null;

      /*********************************************/

       please guide how can i remove the hash['b'] kind of key

     /********************************************/

if(hash['dddjjj'])

{

alert("yes");

}

else

{

alert("no");

}

}

getValue();

# February 27, 2007 1:05 AM

pvanooijen said:

http://blogs.acceleration.net/russ/articles/1743.aspx ?

First hit on a google search "javascript hashtable remove"

JFGI

# February 27, 2007 5:23 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!