Archive for the ‘Object creation patterns’ Category

JavaScript classes

Thursday, May 5th, 2011

OK, think of it as a religious flamewar to the likes of "tabs vs. spaces for indentation". Looks like this particular war is currently (at JSConf and NodeConf) even more heated than it should be. Classes vs prototypes. For or against classes.

I personally don't care about the "winner". The thing is that classes currently don't exist in JavaScript. No such thing. However looks like they might in the next iterations of the language (see latest post from Brendan Eich). Some people miss classes so much that they start calling other things classes or come up with some approximation. Problem is, because classes don't exist, people often mean different things when they say "class".

Sometimes they mean "constructor functions". Sometimes they mean a regular object literal (singleton-type thing. Heck, "singleton" is also open for interpretations). Sometimes they mean an object or a function defined using Crockford's module pattern.

Sometimes it's some completely different home-grown (or library-provided) thingie called klass for example (in my "JavaScript Patterns" book I have one example for educational/thought-provoking purposes). It has to be klass, or _class or something weird. Because class is a reserved word. Unused, but reserved. And one day may be full of meaning. See the problem?

I avoid saying "class". It just doesn't exist. Imagine two months down the road ECMAScript comes up with classes. And they will most certainly not be the classes you may mean today (e.g. classes won't be another name for constructor functions, I'm sure).

So any written text/blog/documentation you've produced will become incorrect and even worse - misleading and confusing.

To summarize:

  • saying "class" today is confusing and takes extra effort to process (what do you mean? what was that again? it doesn't really exist and is not defined in the language, so an extra translation step is required)
  • saying "class" today will read plain wrong tomorrow, will confuse and misinform

Note:
Heck, even I have this "how to define a JavaScript class" post on my other blog. I wrote it years ago when, coming from PHP, I was curious how stuff works in JavaScript. Well I got it wrong then. But fixed it not too long ago because it was top 1 result in google and Yahoo search for "javascript class" and "javascript classes" and I didn't want to continue contributing to the confusion.

Note 2:
To my regret, I couldn't make it to JSConf (aka the best!) nor NodeConf this year (because all girls and women in my life are born in May and it's impossible to travel) so I may be a little off on the level of flamewarfare, but according to Twitter I'm not.

Singleton without a closure

Saturday, July 17th, 2010

Warning: anti-pattern ahead.

Mwahaha, I feel like a ninja. I mean a ninja by Doug Crockford's definition which means someone who finds a mistake in the language's design, decides it's cool and abuses it.

So there you go. Regular expression objects are created only once if you're using a literal. Such an object can be used to store the single instance of a Singleton() constructor.

Implementation

function Single() {
    "strict me not!";
 
    var re = / /;
    if (re.instance) {
        return re.instance;
    }
    re.instance = this;
    this.name = "Foo";
 
}
 
Single.prototype.getName = function () {
    return this.name;
};

Test

var s1 = new Single(),
    s2 = new Single();
 
console.log(s1 === s2); // true
console.log(s1.getName()); // "Foo"
s1.name = "dude";
console.log(s2.getName()); // "dude"

Pros

  • The prototype chain works fine
  • No closures
  • No public properties or globals to store the single instance

Cons

  • It's a hack
  • ES5 defines that reg exp literals should no longer work like this

Verdict

Don't use. Please 🙂

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() {
    return “I am ” + this.name;
  };
  // return this;
};

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!');
  }
};