17 September 2008

Another JavaScript pattern - private members shared between object instances

In this post, I will introduce another pattern to add to my previous post about my JavaScript patterns. In fact, this is an extension to those patterns and combines both patterns together! This is a singleton pattern that creates a constructor!

In this post I will also make use of some aspects of JSquared, so please refer to the JSquared website for more information on those.

So, private members shared between object instances. What does that mean? What it means is that I want to have some private variables and functions which are accessible to multiple instances of a constructor but without them being part of the constructor or the objects the constructor will create. A fairly well known way of achieving this is by making the prototype of my constructor an object built using something similar to my singleton pattern. This would allow public and private members on the prototype of my object. But that will not give me all I wish to achieve this time and it can be a clumsy syntax.

The code I will use to help explain this concept is designed to be a simple panel object. The object will manage a series of panels on a webpage which are linked. Only one panel can be open at a time. Typically one would construct this with a singleton object which finds all instances of the panels in the DOM and adds some handling to each DOM node accordingly. I will do this in a different way. This code example is of course merely a skeleton.

var Panel = new (function() {

 

    //add a DOM load event

    addLoadEvent( function() {

        //get all DIV elements with a class of "panel"

        document.getElementsByClassName( {cssClass: "panel", tags: "div", callback: function() {

            //create a new instance of the Panel constructor for each panel

            new Panel(this);

        } } );

    } );

 

    var panels = [];

 

    function closeAll() {

        for (var i = panels.length-1; i>=0; i--) {

            panels[i].close();

        }

    }

 

    //return the Panel constructor

    return function(panelNode) {

        this.open = function() {

            closeAll();

            //perform the open logic

        }

        this.close = function() {

            //perform the close logic

        }

        //add this instance to the all instances array inside the closure

        panels.push(this);

    }

});



Lets step through each part of this example and see what it does:


var Panel = new (function() {


Create a new variable called Panel using the singleton pattern.



    //add a DOM load event

    addLoadEvent( function() {

        //get all DIV elements with a class of "panel"

        document.getElementsByClassName( {cssClass: "panel", tags: "div", callback: function() {

            //create a new instance of the Panel constructor for each panel

            new Panel(this);

        } } );

    } );


Using JSquared methods add an event handler for when the documents loads. The handler will use another JSquared method to find all elements in the document which are DIVs with a class of panel and for each one run the supplied function which will create a new instance of Panel passing in the DIV node with the class panel that was found. (see the JSquared docs for more info on how getElementsByClassName is used)



    var panels = [];

 

    function closeAll() {

        for (var i = panels.length-1; i>=0; i--) {

            panels[i].close();

        }

    }


These are the private members which each instance of Panel will have access to. We have an array of panels which will get filled with each instance of Panel that is created and we have a closeAll method that loops through each instance of Panel and calls its close method.



    //return the Panel constructor

    return function(panelNode) {


We are going to return a constructor (using the standard constructor pattern). The variable Panel that we created at the top of the code example will now take the value of this constructor. In other words, Panel becomes a constructor which we can create instances of using the new keyword.



        this.open = function() {

            closeAll();

            //perform the open logic

        }

        this.close = function() {

            //perform the close logic

        }


Create open and close methods which will perform those actions. In the open method, we first want to close all the panels ensuring only one can be open at any time. To do that we call the private closeAll method which is available through the closure around Panel.



        //add this instance to the all instances array inside the closure

        panels.push(this);


Add this new instance (this line of code is still part of the Panel constructor) to the private panels array also available through the closure we have created.


To recap, we use the singleton pattern to execute some logic before returning a constructor which is then available to us later on in the page execution. We can use the closure this creates to make private members, declared inside the self executing function which is the singleton pattern. These private members are available to each instance of the constructor but the members are not available anywhere else within any JavaScript - as is usual for a closure of this type.

This can be a very powerful and useful pattern. When building a large application, I believe it is good to keep public members of all objects to a minimum and I also prefer not to use the prototype of an object unless I am using inheritance. This pattern achieves both of these aims in an elegant and encapsulated way.

2 September 2008

Google Chrome

So, its finally happened. Google's next step towards world domination is here, and its a web browser! Its also pretty clever. Indeed, I am writing this post in the new browser.

Its called Google Chrome. The Google Chrome chrome is extremely minimal and I like it. The tabs have certainly taken center stage and got a nice feel to it. It is extremely fast to use and the JavaScript engine appears to be fast and well, I am impressed!

Its well worth a download and a play, and dont forget the developer tools - yes, they are included in the browser.

I wont go into any technical details as Google have done a good (if somewhat unusual) job of explaining things. Check out the website for more information.

My favourite feature so far is the way the browser remembers searches you perform on other sites and makes it so easy for new searches to be performed.

If this is how Google are approaching their application development - and lets face it, no-one expected anything different - then I have high hopes for Android. On that subject, I have recently become the proud owner of an HTC Touch Diamond which is a Windows Mobile phone and I am keeping my fingers crossed that Chrome Mobile is coming soon!

As an aside, being a Webkit based browser, I was hoping that JSquared would "just work". However, I will be doing some testing and you can expect another report soon, especially given the new JavaScript engine.