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.

21 August 2008

The future of JavaScript

For those who have not heard, ECMAScript 4 is no more. That also means that JavaScript 2 is currently at best paused. Some will mourn this as a great loss. I am not one of those.

JavaScript 2 had some very interesting ideas in it, but I am far from convinced that it was the future. I firmly believe that JavaScript 1.x has a long long way to run yet.

It is not often that I will link to an article on Slashdot, but this one piqued my interest.

The future of JavaScript is very much tied up in the present and future of browsers. Much of what I have to say here is also true about future versions of CSS.

The problems we as web professionals face today is not due to a shortcoming of JavaScript or CSS or HTML. They are due to shortcomings of the browsers. Until browsers support the standards, there may as well not be standards.

So we have options. We can introduce new ideas and new technologies which will only be supported by a sub-set of users for a fairly long period and will then fall into a category of technologies we are reticent to use due to the need to support older browsers.

Or, we can wait for the browsers to catch up with the standards so that we can exploit them to the full, with guaranteed compatibility.

Well, I dont fancy waiting something like 4 or 5 or even 6 years for browsers to catch up with the standards, I want to do cool, new and interesting things now. So, we are left with the former of the 2 options I present above.

Of course, the thing which allows us to push forward and use the new technologies of CSS and JavaScript which are being introduced and still provide a good level of cross browser support is JavaScript! Look at how the innovative use of JavaScript, largely by library authors, has driven the W3C and browser vendors to introduce new native features to the browsers. This is only of benefit to us.

I firmly believe that changing the core nature of JavaScript now would undermine a lot of the good work of the last few years and it would also be to deny the true power of JavaScript as it stands today. Yes, there is a barrier to people wanting to learn JavaScript - it can be complex, it is difficult to master - but this also is a good thing. Ultimately the standard of JavaScript development will improve and we don't need a new version of the language to make this happen.

JavaScript is an amazingly flexible language and finding new ways of bending it to our will is going to define the next set of standards, the next set of tools that we want to see, and it is the next set of standards that are far more likely to be adhered to than the current generation.

We must not stifle innovation, we must encourage it. Keeping a massive level of embedded knowledge whilst JavaScript is still at its infancy of true professionalism is the right way forward. Maintaining the core of the language as it stands moving forward must be a good thing. Yes, lets play with other languages in the browser, lets even use and support them, but where JavaScript is concerned, my message is clear - don't go changing!

30 July 2008

Complex assignments

I find my coding style continues to evolve as time goes on. This suggests to me that I am still a long way off getting it right! However, it also gives me the chance to play with new ideas and introduce new concepts to my code.

One new pattern that I seem to now be using more and more is one I call Complex Assignments.

To introduce this, it is useful to look at simple assignment code first. An assignment is simply setting one thing equal to another:

var myVariable = 1;

 

this.myMember = "Some text";

 

this.myMethod = function() {

    ....

}



These are all simple assignments. Sometimes though this is not enough. Sometimes you need to set the value of a variable based on some parameter, eg:

function( myParam ) {

    var myVariable;

    if (myParam === 1) {

        myVariable = "Some text";

    } else {

        myVariable = "Some other text";

    }

}



Now of course this is a trivial example, but you may find yourself needing a more complex set of rules. In that case, the logic around this assignment can become complex. To alleviate this problem we will often delegate the assignment logic into a function. This is perfectly acceptable and actually desirable and in a JavaScript object we can make a private function to do the work:

function myObject() {

    this.someValue = getSomeValue();

 

    function getSomeValue() {

        //do some work

        .....

        return someValue;

    }

}



However, if this function is only going to get called once, there is no need to make it a named function. In fact I find it neater to make it an anonymous function. Of course, if its an anonymous function that only gets run once, we can make it a self invoking function. To rewrite the example above:

function myObject() {

    this.someValue = (function() {

        //do some work

        .....

        return someValue;

    })();

}



In this instance, the code looks very similar (if somewhat neater). But, with this anonymous self invoked function, we are actually creating another level of scope which will get destroyed once the function has been executed. This can be very useful and can be very efficient. I also think the code is simple to understand and even better encapsulated.

This is particularly useful for the setting of constant like variables. I find myself using this pattern more and more as I find more occasions where I want a function to be used to assign a value to a variable.

17 July 2008

Coupling, API surface area and change change change

Recently I started a new job focusing much more heavily on JavaScript than before and having been in this new role for a little while and having got the release of JSquared 1.1 out of the way, I have had some time to think about what I have learnt so far.

Firstly it must be said that I am thoroughly enjoying working more heavily with JavaScript and I have already learnt some wonderful and interesting things about the way that JavaScript operates and how to make it go a bit faster. No, a LOT faster! I will be talking about some of these things in the future and applying that knowledge to JSquared!

Also, I have recently read the excellent book from Douglas Crockford espousing about the good parts of JavaScript. However, what I saw in my new role did not conform too closely if at all to the Crockford way of thinking (which I happen to largely share).

First off, the code that exists here is of a very high quality and is well organised, but I have started to realise that there are a number of things I would look to do differently if we could re-write all the code from scratch.

The code has become fairly tightly coupled over time with one object requiring and expecting another object to exist and the second object creating a back reference to the first. There are a number of circular references if one looks through the various objects closely enough.

References to objects are being passed around freely and there is little control being exercised over how values should be accessed and a distinct lack of singletons being used when I believe they should be.

This leads to a very large API surface area. By this I mean that there are a large number of methods that each object needs to expose and a large number of object references being passed around when a smaller API with singletons where appropriate would be simpler.

The combination of the above two things leads to a problem. If you want to rebuild all or part of an object, it becomes more difficult as the objects have very little private code. If an object exposes just a few methods and properties as its API, and retains the rest of its working as private internals, it becomes much easier and simpler to re-write or add to it.

This is a JavaScript application which undergoes constant change by multiple people. Whilst this is good, it does mean that there are more and more objects with wider and wider surface areas. I personally believe that this will lead to the need for a complete re-write of large parts of the application sooner.

This brings me on to my final point, a positive and a negative point. The application is harder to learn and takes longer to become confident with because of this large API surface area. I enjoy that though as I want the challenge!

12 July 2008

JSquared 1.1

It is with pleasure that earlier today I was able to announce the launch of JSquared 1.1. See the blog and the website for more details.

30 June 2008

Not lovely...

Well, its not often that I have had a bad word to say about Mozilla Firefox. However, for the second time in a week, I now do.

I have been aware of issues with the Mozilla implementation of eval for some time, but the latest exposure was news to me and seemingly many others.

Full details can be found here. There is no reliable way round that I can find as yet so I will continue along the assumption that in the JavaScript world, nothing is safe.

I will still use a module pattern (as I have discussed before in a previous post) and I will still call "private" members private. I will also continue to discourage the use of evil eval.

Douglas Crockford has a few things to say about Firefox in general and had his own comments about this latest issue.

I am deeply disappointed frankly. Firefox 3 ruined my week last week (well, truthfully, Firebug was as much to blame) and now this. I suppose its nice to see that other browser vendors make mistakes!