Archive for the ‘Patterns’ Category

Prototype

Monday, September 14th, 2009

The prototype is an object that every function gets automatically, as soon as you create it.

You can add properties and methods to the prototype property of your constructor function. Then all objects created with this constructor will have access to everything you add to the prototype.

var Person = function(name) {
  this.name = name;
};
Person.prototype.say = function() {
  return this.name;
};

if you add properties to the prototype of a "normal" function, meaning function that you don't invoke as a constructor, these will not be used.

Using the prototype

var adam = new Person('Adam');
alert(adam.name); // "Adam"
alert(adam.say()); // "Adam"

As you can see the object has access to the prototype’s members.

The prototype properties are shared among all objects.

Rule of thumb

And a general rule of thumb – the properties and methods that are meant to be reused and shared and inherited, should be added to the prototype.

Enforcing `new` in constructors

Monday, September 14th, 2009

A constructor is just a function and failing to invoke a constructor with new leads to errors. Not syntax errors but logical errors. Following a naming convention can certainly help, but it doesn't enforce the correct behavior. If you invoke a constructor without new, then this will refer to the global object, called window in browsers.

Here's a pattern that helps you make sure your constructor always behaves as constructor. Instead of adding all members to this, you add them to that.

In this implementation that is the same as this unless this is window which means someone forgot to use new.

function Person() { 
  var that = (this === window) ? {} : this;
 
  that.name = name;
  that.say = function() {
    return "I am " + that.name;
  };
 
  return that; 
}

window is only in browsers

Another way, if you work in non-browser environment is to check if this is an instance of your Person constructor.

Or name-agnostic, general-purpose way is to use arguments.callee instead of hard-coding the constructor name.

this instanceof Person
this instanceof arguments.callee

Constructor naming convention

Monday, September 14th, 2009

Constructors are just functions, it all depends on how they are invoked - with or without new.

So a naming pattern is pretty useful to help you visually distinguish between the two. It gives you a clue that the uppercase functions are meant to be called with new.

MyConstructor
myFunction

Constructors

Monday, September 14th, 2009

A simple way to create objects in JavaScript is using object literal notation. An other way, a bit more involved is to use a constructor function.

var adam = new Person("Adam");
adam.say(); // "I am Adam"

The invocation of the constructor looks a bit like a class in other languages, but the constructor is still just a function. (JavaScript doesn’t have classes). So the constructor is the blueprint, the recipe for the object.

And here's how the constructor Person is defined, it adds all members to the this object.

var Person = function(name) {
 
  this.name = name;
  this.say = function() {
    return "I am " + this.name;
  };
 
};

When you define a constructor, something like the following happens behind the scenes. It's as if you defined an object using the literal notation and then returned it.

var Person = function(name) {
  // var this = {};
  this.name = name;
  this.say = function() {
    returnI am ” + this.name;
  };
  // return this;
};

Singleton

Monday, September 14th, 2009

According to Wikipedia:

...the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object.

How does this apply to JavaScript? Well, in JavaScript there are no classes, just objects. So when you create a new object, there's no other object like it and the new object is already a singleton.

var obj = {
  myprop: 'my value'
};

This is an example of creating a simple object in JavaScript using the object literal and it's also an example of a singleton.

Using new

The other question is how about if you want to use the Java-like syntax:

var obj = new Constructor();

This is more of classic-like syntax so the idea of a singleton here is that when you use new to create several objects using the same constructor, you should only get one object.

var obj = new Constructor();
var obj2 = new Constructor();
alert(obj === obj2); // true

obj is created only the first time the constructor is called, the second time (and the third, fourth, etc) the obj created the first time is returned. How to achieve this in JavaScript?

Basically you need your Constructor to cache the object instance this once it's created and then pull this instance the second time it's called. You can cache the object instance:

  • in a global variable - not recommended, general principle is that globals are bad, plus anyone can overwrite this global, even by accident;
  • in a Constructor property - functions in JavaScript are objects, so they can have properties. You can have something like Constructor.instance and cache the object there. This is a nice clean solution with the only drawback that this property is accessible and code outside of yours might change it, so you lose the instance;
  • wrap the instance in a closure

Let's take a look at an example implementation of the last option.

function Constructor() {
  return Constructor.getInstance(this);
}
Constructor.getInstance = function(){
  var instance;
  return function(that) {
    if (typeof instance === 'undefined') {
      instance = that;
    }
    return instance;
  }
}();

And a simpler new

Here's another way to do the class-like singleton. Secret sauce: using a closure to keep the reference to the single object and then rewrite the constructor.

function Single() {
 
  var instance = this; 
 
  // add more to this…
 
  Single = function (){
    return instance;  
  };
}
 
// test
var my1 = new Single();
var my2 = new Single();
alert(my1 === my2) //true

Init-time branching

Monday, September 14th, 2009

Probably virtually every web developer has done something like this at one point or another:

function myEvent(el, type, fn) {
  if (window.addEventListener) {
    el.addEventListener(type, fn, false);
  } else if (window.attachEvent) {
    el.attachEvent("on" + type, fn);
  }
}

This is absolutely normal, browsers are different, we have to take this fact into account and branch our code. One way to improve similar bits of code is by branching only once, when the function/method is defined as opposed to every time it's called. Like this:

if (window.addEventListener) {
  var myEvent = function (el, type, fn) {
    el.addEventListener(type, fn, false);
  }
} else if (window.attachEvent) {
  var myEvent = function (el, type, fn) {
    el.attachEvent("on" + type, fn);
  }
}

This way you get browser-dependent myEvent() function and there's no branching every time the function is called. While this may sound unnecessary, it could have an impact when a function is called many times in performance-critical situations, such as during drag-n-drop.

In a drag-drop case, it's likely that you need to get the current (computed) style of an element and also set it. Getting the computed style is different in browsers and is an ideal candidate for load-time branching. This is how it's done in the YUI DOM utility (source code), where this pattern was actually isolated from.

The DOM utility does more stuff, but the purpose of simply demonstrating the pattern you can say that it does something like:

// load-time branching
if (document.defaultView && document.defaultView.getComputedStyle) {
  var getStyle = function(el, property) {
    return document.defaultView.getComputedStyle(el, '')[property];
  }
} else if (document.documentElement.currentStyle) {
  var getStyle = function(el, property) {
    return el.currentStyle[property];
  }
}
 
// usage
var style = getStyle($('something'), 'fontWeight');

Another benefit of load-time branching is that you can branch only once and define multiple functions. For example if you've detected that the browser supports window.addEventListener it's very likely that it will support window.removeEventListener as well and not window.removeEvent. This should be approached carefully though, so that you keep in mind to branch based on object/feature detection and not on browser detection. For example don't be tempted to define getStyle() based on detection for window.addEventListener, although it will most likely work.

Using literals

Monday, September 14th, 2009

Array literals

In JavaScript you can define an array like this:

var a = new Array();

A better pattern to do so is by using the array literal, basically a comma-delimited list of values, wrapped in square brackets:

var a = []; // array with no elements
var a = [1, 2, 3]; // array with three elements
var a = [[1, 2, 3], ['a', 'b', 'c']]; // array of two arrays

Object literals

Similarly, an empty object can be defined as:

var o = new Object();

A much better pattern is to use the object literal:

var o = {}; // empty object
var o = {p: 'one'}; // object with a "p" property
var o = { 
  prop: 1,  // a property
  meth: function() { // a method
    alert('Boo!');
  }
};

Separating behavior

Monday, September 14th, 2009

The modern understanding of a web page is that it consists of three distinct parts:

  1. Content (HTML)
  2. Presentation (CSS)
  3. Behavior (JavaScript)

These should be kept separate, ideally each in its own file (or files). What it means for JavaScript is that there should be no inline such as onclick, onmouseover, etc. Ideally there should be little to no inline scripts.

The idea is that content (the text on the page) is independent of:

  • how it looks like, so the page should be usable even with CSS disabled, or not supported by the browser, and
  • how it behaves, meaning the page should be usable even with JavaScript disabled. The content should be accessible independent of any mouseovers, animations, and so on.