May. 10th, 2013

webdev: (Default)
Out of the box, JavaScript has no implementation of the classical OO concept of "classes." In my experience, this is one of the biggest stumbling blocks for people coming to the language from classical OO languages like C++ or Java. Prototypal inheritance is also something of a challenge, though generally it's so well-hidden you won't be encountering it unless you go digging. Despite these barriers, JavaScript classless existence gives it a dynamic nature that classic OO languages just don't have.

So if there are no classes, how do you create objects and templates for objects in JavaScript? There are actually three methods.

Constructor Functions

In JavaScript, you can create a constructor function that applies properties and methods and initialization routines to an empty object and then returns it. JavaScript has a special built-in functionality for this using the new keyword: when you invoke a function with the new keyword, JavaScript will create a new empty object and then invoke the function with the empty object as the invocation context (in other words, within the function the this keyword will refer to the new object). JavaScript will automatically return the modified context when the function is done executing, or you can do it yourself by explicitly returning this when you're done. Here's a simple example:
function constructorFunction() {
  this.myNumber = 10;
  this.myMethod = function() {
    console.log('Method was called');
  }
  return this;
}

var myNewObject = new constructorFunction();
console.log(myNewObject.myNumber); // will output 10 to console.
myNewObject.myMethod(); // will output 'Method was called' to console.

Constructor functions have the benefit of having a great deal of flexibility. You can create very complex objects and have all of the creation and initialization code nicely encapsulated within the constructor.

On the other hand, my experience has shown me that constructor functions tend to confuse new JavaScript programmers, especially those with experience with classic class-oriented languages. I think it's because the new keyword makes it look like you're instantiating a member of a class, but you're not. The mechanisms are completely different, even though the result is a new object.

Object Literals

You can simply define a new object using literal notation. I use this method most often when creating singletons.
var mySingleton = {
  intProp: 10,
  strProp: "hello world",
  myMethod: function() {
    console.log(this.strProp);
  }
};
mySingleton.myMethod(); // will output "hello world" to the console.

Literals are a fast, down-and-dirty way of creating one-off objects. The disadvantage is that it's kind of hard to do extensive initialization, unless you specify a method as part of your literal that you can then invoke. Encapsulation is also a challenge.

Object.create()

By far my favorite way to create new objects is to use the create method on the global Object object. Object.create takes two parameters:

prototypeObject: An existing object that will serve as the prototype for the new object.
propertiesObject: An optional map of properties along with their descriptors, to be copied onto the new object. (See JavaScript Property Descriptors for an in-depth explanation.)

When you invoke Object.create it creates a new object, sets its prototype to prototypeObject and then copies the properties from propertiesObject (if it was provided) onto the new object, and then returns the new object.

This method basically allows you to use any object as a template for a new object. In my opinion, this really helps clarify JavaScript's prototypal inheritance, so I generally prefer this method.