JavaScript Object Creation Patterns

What are the differences in creating an object by way of simple function invocation, vs using a constructor vs creating an object using the object literal notation vs function application?

To make sure we’re all on the same page, a quick refresher of what an object actually is in JavaScript…

What is an object in JavaScript?

  • An object is an unordered mutable keyed collection of properties. Each property is either a named data property, a named accessor property, or an internal property. I discussed JavaScript properties in depth here.
  • The ECMAScript language types are Undefined, Null, Boolean, Number, String and Object.
  • The simple types (primitives) of JavaScript are members of one of the following built-in types: Undefined, Null, Boolean (true and false), Number, and String.
  • All other values are objects. Function, String, Number, RegExp etc all indirectly inherit Object via their prototype property, which has a hidden link to Object. Try not to get confused about the fact that we can have for example a String primitive which isn’t an object and we can have a String object by calling the String constructor. See the ES3 and ES5 spec 15.5.
  • All objects have a prototype. I explain JavaScript prototypes here.
  • An object created from a function has a “prototype” property (an Object) (seen below in the red box) (whether invoked as a constructor or function). It has a property which is a constructor function (seen below in blue box) and a hidden property (a link) to the actual Object.prototype (seen below in the pink box).
  • An object created by means of an object literal inherits straight from (is linked to) Object.prototype. So the “prototype” property doesn’t exist, but there are other ways to access it. Problem is… how to access it varies from browser to browser.

internals of a function object

internalsOfAfunctionobject

Every function is also created with two additional hidden properties: the functions context and the code that implements the functions behaviour.

Object creation

On invocation, every function receives 2 hidden parameters. this and the arguments array (which provides access to all the arguments that were supplied to the function on invocation). The value assigned to this is determined by how the function was invoked. We’ll look at this in the following sections.

Object creation via function invocation

Pros

Best suited for creation of one-time on-demand objects.

Cons

If a function is not the property of an object literal, when you invoke it, this will be bound to the global object. Often not what you’re expecting. A mistake in the design of the language. As you can see in the following code, the this of the local scope (kimsGlobalFunction)

aFunctionInItsOwnScope

correct this is global

Now here you can see when we invoke the local function, the this is bound to the global object. That’s a mistake in the language. When innerFunction is invoked, the this of that function is also bound to the global object.


InsideaFunctionsOwnScope

Line 18 above alerts undefined, because that doesn’t belong to the global object.


NotCorrectThisIsGlobal

-

Object creation via constructor

What is a constructor in JavaScript?

It’s a function, nothing more. It’s how it is invoked that determines it as a constructor.

What does it look like?

(function () {
   // Create a constructor function called MyFunc.
   var MyFunc = function (aString) {
      // The following variable is private.
      var privateString = aString;
      // Access it with a privileged method.
      this.publicString = function () {
         return privateString;
      }
   };

   // Prefixing with new means we're now using the function as a constructor.
   // So we use PascalCase rather than camelCase, so users of MyFunc don't invoke without the new prefix.
   var myFunc = new MyFunc('sponge bob');
   alert(myFunc.publicString());
}());

Pros

Great for re-use. Creating a constructor and assigning members to it’s prototype, mean that every time you create an object from the constructor using the new prefix, the new object uses the same prototypes members. This can save big time on memory if you are creating many objects with the constructor.

Cons

Con 1

What happens when someone invokes a constructor function directly without the new prefix?
The this of the function will not be bound to the new object, but rather to the global object.
so instead of augmenting your new myFunc object, you will be clobbering the global object.
myFunc‘s this would refer to the global object

What counter measures do we have at our disposal to make sure this doesn’t happen?
Naming conventions.
Enforcing new is used with JavaScript constructor functions? pg 45 – 46 of Stoyan Stefanov’s JavaScript Patterns book addresses this. Problem is, those patterns all have significant flaws. So, you really need to weigh up the pros and cons. Maturity of your development team should also play a role in your decision here. It may be worth taking a safer route and employing an object literal if developers are likely to omit the new prefix on an intended constructor invocation.

Object creation via object literal

What does it look like?

Line 12 executes the creation and return of an object with a property called publicString.

// In its simplest form:
var myObject = {};

(function () {
   var myFunc = (function () {
      // private members
      var privateString = 'Spong Bob';
      // implement the public part
      return {
         publicString: function () {
            return privateString;
         }
      };
   }());

   alert(myFunc.publicString());
}());

Pros

Pro 1

The this is bound to where you’d expect it to be (adherence to Principle of least astonishment (POLA).
When a function is stored as a property of an object literal, it’s a method. When a method is invoked with this pattern, this is bound to the object. In the below section of code, when execution is on line 05

(function kims() {

   var myObjectLiteral = {
      myProp: 'a property value',
      myFunc: function () {
         alert(this.myProp);
      }
   };
   myObjectLiteral.myFunc();
}());

Here you can see that the value of myFunc‘s this argument is in fact the myObjectLiteral.

this value

In which case because a function is an object, and a variable is a property, then the same must apply to invoking a function of a function? No. The vital word here is “literal”… As above… “When a function is stored as a property of an object literal

Pro 2

Best suited for creation of one-time on-demand objects.

Cons

As with storing members in a function, be it a function you intend using new with (a constructor), or just by invoking the function, members will not be shared between instances of the prototype. This means that if you create 200’000 myObj object literals as I did in the test above, you will have 200’000 separate add functions in memory. The same goes for adding the add function to the constructor without adding it to the constructors prototype.

Object creation via function application

There is one more object creation pattern. Function application. I’ve discussed this in depth in the following three posts. Check them out.

http://blog.binarymist.net/2012/04/29/extending-currying-and-monkey-patching-part-1/

http://blog.binarymist.net/2012/05/14/extending-currying-and-monkey-patching-part-2/

http://blog.binarymist.net/2012/05/27/extending-currying-and-monkey-patching-part-3/

Speed Testing

Object creation is significantly slower using constructors with no prototype than it is using object literals. Now I did some more testing around this and got some surprising results. Using Chromium, V8 is doing some severe optimisation with object creation using constructors. The more members I added to my test constructor and object literal, the more it became noticeable.

var runTestTimes = function (iterations) {
   var test = function () {
      var constructorIterations = 1000000;
      var objLiteralIterations = 1000000;
      var constructorStart;
      var objLiteralStart;
      var constructorTime;
      var objLiteralTime;
      var MyFunc = function () {
         var simpleString = 'simple string';
         var add = function () {
            return 1+1;
         };
         add();
      };

      constructorStart = new Date();
      while (constructorIterations--) {
         var myFunc = new MyFunc();
      }
      constructorTime = new Date - constructorStart;

      objLiteralStart = new Date();
      while (objLiteralIterations--) {
         var myObj = {
            simpleString: 'simple string',
            add: function () {
               return 1+1;
            }
         };
         myObj.add();
      }
      objLiteralTime = new Date - objLiteralStart;

      console.log('constructor: ' + constructorTime + ' object literal: ' + objLiteralTime);
   };
   while (iterations--) {
      test();
   }
};
runTestTimes(10);

Yields the following results:

constructor: 32 object literal: 19
constructor: 25 object literal: 18
constructor: 25 object literal: 17
constructor: 25 object literal: 18
constructor: 26 object literal: 17
constructor: 25 object literal: 18
constructor: 25 object literal: 17
constructor: 25 object literal: 17
constructor: 25 object literal: 18
constructor: 25 object literal: 17

By simply adding another function to the constructor and the object literal, the results in chromium swung to favour the constructor.

// add this function to the constructor.
var subtract = function () {
   return 1-1;
};

// add this function to the object literal.
subtract: function () {
   return 1-1;
}

Reducing the number of iterations from 1’000’000 to 200’000 because the same code run in Firefox crashed it… Yielded the following in Chromium:-

constructor: 5 object literal: 6
constructor: 3 object literal: 5
constructor: 3 object literal: 5
constructor: 2 object literal: 5
constructor: 3 object literal: 4
constructor: 2 object literal: 5
constructor: 2 object literal: 5
constructor: 3 object literal: 4
constructor: 3 object literal: 5
constructor: 2 object literal: 5-

and yielded the following using the Firefox JavaScript engine SpiderMonkey:-

constructor: 701 object literal: 21
constructor: 729 object literal: 17
constructor: 705 object literal: 17
constructor: 721 object literal: 18
constructor: 727 object literal: 20
constructor: 723 object literal: 18
constructor: 726 object literal: 18
constructor: 727 object literal: 20
constructor: 728 object literal: 17
constructor: 736 object literal: 18-

When I moved the add and subtract functions from the constructor to the constructors prototype, the speed results in chromium didn’t yield any noticeable difference. in Firefox

the average went from 854ms to 836ms. The change looked like the following:

var MyFunc = function () {
   var simpleString = 'simple string';
};

MyFunc.prototype.add = function () {
   return 1+1;
};

MyFunc.prototype.subtract = function () {
   return 1-1;
};

I decided to create some tests on jsperf to provide repeatable results. What’s interesting is you don’t have to change a lot to get completely different results, so if you’re concerned about performance, it really pays to test it. I think the tests on jsperf are probably a bit more truthful. here they are.

Summary

There are many more pros and cons of each invocation pattern. I’ve listed the ones that I think are the most important to understand. There is no right or wrong pattern to use for everything. Consider your target audience and what the majority of them may be using in terms of browsers. Consider the maturity of your development team. Benchmark the different approaches, but don’t fall into the trap of micro optimisation, or optimising for a single browser or JavaScript engine unless that’s all your users are using. Choose the pattern that provides the most wins for the given situation. I didn’t test in I.E, but as you can see, the JavaScript engines I did test with do things very differently.

Tools like

  1. Google Page Speed
  2. Google Speed Tracer
  3. Chromiums Profiler

Will help you focus on the areas that matter most.

There are of course many other areas to look at when it comes to “is your app delivering an acceptable user experience”.
Take a few steps back from your situation. You only have so much time. Spend it wisely.
There are many good wins to be had for little cost. Yahoos YSlow has a bunch.
Many books also address this in depth:

  1. Even Faster Web Sites by Steve Souders
  2. High Performance Web sites by Steve Souders
  3. High Performance JavaScript by Nicholas Zakas

There is also a good read on how V8’s full and optimising JIT compilers optimise JavaScript.
I’ve found that most of it’s intuitive and if your using good design and coding principles, in “most” cases your safe, but it’s still worth the read.

  1. As developers we try not to change classes on the fly. deleting or adding properties to hot objects in JavaScript negatively effects the optimising compiler.
  2. We don’t use floats when we only need ints.
  3. In JavaScript, use Arrays when the property names are small sequential integers. Otherwise, use an object. JavaScript Arrays are not like arrays in most other languages. They are simply objects with some array like characteristics.
  4. Assign your array elements as early as possible. 
  5. Don’t delete elements in an array, or leave elements empty.

JavaScript is a very dynamic language. Use its dynamic nature cautiously if you want performant code. Most importantly, favour read time convenience over write time. Your code is going to be read many more times than it’s written.

At this stage, V8 is way ahead of the other JavaScript engines in terms of performance. Node.js uses the V8 engine and enjoys the same incredible performance.

Inheritance

Prototypal inheritance is more OO than classical inheritance.
With prototypal inheritance, a child object only needs to inherit the parent objects specific properties pertinent to it.
With classical inheritance, a child object inherits all the parent objects members, even the ones that it should have no knowledge of.

Hopefully most of us already know to favour composition (aggregation) over inheritance. Be it classical or prototypal. I’ve explained some techniques of how this can be done effectively in JavaScript in the above three posts.

Angus Croll is a master at explaining these concepts, so be sure to check out his post here.

Even the Java creator James Gosling says he’d do away with classes or classical inheritance if he could write the language again.
Inheritance can be an anti pattern as it’s tight coupling. Sub classes inherit everything no matter what. Prototypal is opt-in.
One of the Fluent Conference talks by Eric Elliott on why we should steer away from classical inheritance goes to say the following:

Classical Inheritance is Obsolete
“Those who are unaware they are walking in darkness will never seek the light.” —Bruce Lee
In “Design Patterns”, the Gang of Four recommend two important principles of object oriented design:
1) Program to an interface, not an implementation.
2) Favour object composition over class inheritance.
In a sense, the second principle could follow from the first, because classical inheritance exposes the parent class to all child classes. The child classes are all programming to an implementation rather than an interface. Classical inheritance breaks the principle of encapsulation, and tightly couples the child classes to its ancestors.
Why is the seminal work on Object Oriented design so distinctly anti-inheritance? Because classical inheritance causes several problems:
Tight coupling. Classical inheritance is the tightest coupling available in OO design. Descendant classes have an intimate knowledge of their ancestor classes.
Inflexible hierarchies. Single parent hierarchies are rarely capable of describing all possible use cases. Eventually, all hierarchies are “wrong” for new uses—a problem that necessitates code duplication.
Complicated multiple inheritance. It’s often desirable to inherit from more than one parent. That process is inordinately complex and its implementation is inconsistent with the process for single inheritance, which makes it harder to read and understand.
Brittle architecture. Because of tight coupling, it’s often difficult to refactor a class with the “wrong” design, because much existing functionality depends on the existing design.
The Gorilla / Banana problem. Often there are parts of the parent that you don’t want to inherit. Subclassing allows you to override properties from the parent, but it doesn’t allow you to select which properties you want to inherit.

Additional Sources:
ECMA-262 edition 5.1
JavaScript The Good Parts.
JavaScript The Definitive Guide.
Eric Elliott’s talk at the fluent conference May 28-30, 2013.

About these ads

Tags: , , , , , ,

One Response to “JavaScript Object Creation Patterns”

  1. Kim Carter Says:

    language types are Undefined, Null, Boolean, Number, String and Object. All other values are objects. Function, String, Number, RegExp, Array, Boolean, Number all indirectly inherit Object via their prototype property, which has a hidden link to Object. These are object-like in that they have methods. Having the link to Object via their prototype doesn’t make them objects. In JavaScript objects are mutable keyed collections. You really have to dig into the ES3 and ES5 specs to get this. Anyone got any other thoughts on this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

Join 216 other followers

%d bloggers like this: