Object-Oriented JavaScript Follow-Up Part 1: Method

Published 17:43 on 08 October, 2010

Back in May, 2006, I wrote an article entitled Object Oriented JavaScript. It was an exercise in both writing a useful tutorial, and a brain-dump of various things I had learned about writing object-oriented code on the client side. It quickly became apparent—as the article was linked to from a multitude of my favourite web standards development sources—that the tutorial itself was helpful; the comments burgeoned, and the traffic rocketed.

When I read that article now, however, it bothers me. The tutorial is still good although the information within is somewhat dated; and my personal experience, knowledge, and general approach to writing JavaScript has changed quite drastically. The fact that the article still receives a consistently high number of unique visitors on a daily basis, when I no longer agree with all the content within it, bothers me even more. With that in mind, I have decided to write an update that looks at OOJS as I would currently use it.

The resulting post has become quite extensive, so I’ve decided to split it into two separate articles. This first one will cover some development theory, whilst the second will dive into JavaScript coding specifics.

A note on the name

A friend of mine recently quoted this little gem in his Twitter stream:

Java is to JavaScript as Ham is to Hamster.

Enough said.

Is it object-oriented?

In my original article I stated that JavaScript was not an object-oriented language, but rather an object-based language. This was entirely unfair on JavaScript, and I’d like to fix that:

JavaScript is an object-oriented language. However, it breaks away from more conventional object-oriented languages by implementing prototypal inheritance, instead of classical inheritance. This is a Very Good Thing™ (although that seems to be a matter of opinion). More on that later.

First principles for JavaScript programming

Before I start, let me be clear that there are first principles of programming that are language agnostic. We’re going to look at a couple of those, but I’d also like to discuss a few of the more JavaScript specific principles first; those that relate to the cross-browser web standards environment. Finally, I’m aware that I’m really only scratching the surface of some of these topics. I don’t really want to muddy the water here by waxing lyrical on good development practices, so if you’re after more depth, I’d recommend researching them via the search engine of your choice:

Proper separation of the behavioural layer

Above everything else, it’s important to keep your content and markup (HTML), presentation (CSS), and behavioural (JavaScript) layers separate. Why is that important? Well if one or more of those layers are missing or broken (with the obvious exception of the core HTML), the others should still function as intended. Ultimately this makes presentation and behaviour optional, and a user might turn them off—via their browser settings—should they so desire. Alternatively, the user may include custom presentation or behaviour to aid a particular use-case.

In JavaScript, proper separation requires making use of the DOM to bind behaviour to HTML elements via element identifiers (i.e. the id or class attribute) in your source code. The alternative would be to write JS directly into the HTML, via event attributes such as onClick=”” or via the javascript: pseudo-protocol in the href attribute. This is not a good practice and I heartily recommend against it.

Graceful degradation

Graceful degradation is a well known software engineering concept which involves writing your code to take advantage of awesome feature X, unless awesome feature X is unavailable, in which case degrade to use slightly-less-awesome feature Y (assuming that too is available).

In web development terms this might mean making use of an amazing JavaScript date picker widget on a text-based input box, and just degrading to server-side date validation if JS is not turned on in the browser. It could also mean making use of the latest CSS3 styling techniques but degrading to use CSS2 techniques in less capable browsers.

In short; build everything in the most up to date browser, making use of all it’s wonderful modern features, and then go back and make sure the site is still usable when any of those features are not.

The problem with approaching the issue from this direction, however, is that you are saying to your users: “You (or your browser) are incapable of handling the full experience we want to present, so here’s a cut-down version.” This pretty much flies in the face of user-centric design, and good user experience. With that in mind, we’d be better using…

Progressive enhancement

Progressive enhancement involves approaching the problem from the other direction. You should design for the user-agent with the least capabilities and add functionality for more capable browsers afterwards.

In web terms this means developing and designing with nothing but the base features of HTML in mind, and then enhancing those features (or the features of the browser interpreting that HTML) by attaching CSS and JS to the HTML via element identifiers like IDs and classes.

The final outcome of these two approaches might be very similar, but the subtle difference is that you are giving more attention to the less capable user-agent when you progressively enhance.

The most common use-case for progressive enhancement is the support of a non-JS experience.

DRY (Don’t Repeat Yourself)

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system. This means abstracting code into shared functions and objects whenever you find you are repeating yourself, and attempting to maintain a single source of truth in every aspect of your system.

DRY is a well known paradigm in software engineering, and as such, should be applied in every detail of your JavaScript code.

Refactor early, refactor often

Further to the principle of DRY, it is important that if you spot a potential issue in your JavaScript code you fix it. The more small refactors you do, the less time-consuming big refactors you are likely to need to do later on.

Once you’re refactoring often, you’ll be able to…

Make it work, make it right, make it fast

The first iteration of your code should only look to reach the level of functionality defined in the functional specification. Once this has been achieved, refactor to improve the way it works—so the code is “right” in your opinion. This may very well mean a complete overhaul of architecture, but you will be able to concentrate much more specifically on that since you already have it working. The final stage in this development cycle is to optimise your code for performance and efficiency; premature optimisation is a fundamental mistake in development.

Useful resources

When it comes to general development, there are a veritable plethora of resources out there, but my recommended starting point is the book The Pragmatic Programmer, by Andrew Hunt and David Thomas. This book outlines quite a few paradigms that should get you thinking about the way you develop.

Important things to understand

Pure JavaScript

In this age of JavaScript libraries and frameworks, it’s important to make sure you understand core JavaScript functions, objects, and methods. Although your library of choice may clean up any cross-browser issues you may encounter, it is always important to understand exactly how you are interacting with JavaScript as a language.

Useful resources:

The Mozilla Developer Centre section on JavaScript is an invaluable reference resource when writing pure JavaScript. Also, make sure you own a copy of JavaScript: The Definitive Guide by David Flanagan.

The DOM

The Document Object Model is an entirely separate beast to JavaScript, but is implemented natively within it. There are also DOM libraries for other languages that implement the W3 DOM specification when dealing with XML and SGML files.

Understanding the DOM in JavaScript is essential when designing and developing interactions with your HTML and CSS. Thankfully all JavaScript libraries abstract out the pitfalls of DOM scripting so that you don’t have to, but as before, it’s still important for you to understand how so that you can maximise your efficiency in using said library.

Useful resources:

Once again the Mozilla Developer Centre provides an excellent DOM reference section, although it is slightly skewed in favour of the Gecko browser engine. You can also find plenty of information on the DOM at the W3C site.

Interaction with the browser

When writing client-side JavaScript, it is important to take into account how HTML, CSS, and JavaScript interact with the browser directly. At every available opportunity, you should attempt to make sure you are not contradicting the browser, and that you are not rewriting interactions that are already well handled by the browser and operating system.

A good example of this is to make sure you do not break the “back” button. Often this can be achieved by simply using the window.location.replace() method to control which pages appear in the browser history.

Libraries

Using libraries in JavaScript has become standard practice. A JavaScript library exists to save time and effort, and to provide a single source of truth (as discussed earlier) for many common tasks within that language.

A JavaScript library provides you a toolbox full of handy devices to make your life easier. It needs to be treated as such, and not as a language in its own right. It is very important to understand the core structures of JavaScript, and how the library of your choice interacts within those structures and your own code.

Every library is different and has its own pros and cons. I’m not going to go into my opinion of those here; perhaps that’s something for another post. They do, however, all interact somewhat differently with JavaScript, and it’s important to understand how the library you choose does that specifically.

Summary

Hopefully that should get you in the right frame of mind to develop high quality JavaScript code. In the second half of this article I will be looking at specific use of JavaScript in regard to object-orientation.

Continue reading part 2 of my object-oriented JavaScript follow-up…