Like it!

Join us on Facebook!

Like it!

Object literals vs constructors in JavaScript

I want to use JavaScript in a more object-oriented way.

JavaScript is, quite surprisingly, an object-oriented programming language that can be confusing when it comes to object creation. In this article I want to sort it out for good.

Literals and constructors

In JavaScript there are two ways to create an object: the constructor function or the literal notation. Take a look below:

// constructor function
function Website() {};

// literal notation
var Website = {};

Either way you have just created a JavaScript object called Website. The main difference here is what you can do with it. With the constructor function notation you create an object that can be instantiated into multiple instances (with the new keyword), while the literal notation delivers a single object, like a singleton.

Defining methods and properties

Objects in JavaScript have methods and properties, whether they are built with the constructor function or with the literal notation. Let's see how to define them:

// constructor function
function Website() {
    this.url = 'http://www.internalpointers.com';
    this.printUrl = function() {
        console.log(this.url);
    };
};

// literal notation
var Website = {
    'url': 'http://www.internalpointers.com',
    'printUrl': function() {
        console.log(this.url);
    }
};

Using the objects

Besides the syntax, the two objects differ in how you use them. If the object has been created with the constructor function, you must instantiate it first. On the other hand the literal-notated one is ready for use:

// constructor function
var InternalPointers = new Website();
InternalPointers.printUrl();

// literal notation
Website.printUrl();

Where's the constructor of literal notation?

It is clear that with the literal notation you can't have a constructor, namely you can't initialize your object unless you add a custom init() function. Instead, with the constructor function you can pass additional parameters to the object through the built-in constructor, like that:

// constructor function
function Website(protocol) {
    this.protocol = protocol;
    this.url = this.protocol + '://www.internalpointers.com';
    this.printUrl = function() {
        console.log(this.url);
    };
};

var InternalPointersHttp  = new Website('http');
var InternalPointersHttps = new Website('https');
InternalPointersHttp.printUrl();   // http://www.internalpointers.com
InternalPointersHttps.printUrl();  // https://www.internalpointers.com

Instantiation versus singleton approach

The previous snippet reveals another important property: with the constructor function you can instantiate how many objects you want, and they will be all unique. With the literal notation you always deal with the original object (which is a singleton, remember?), even if you define a new variable with the object as value:

// literal notation
var original = { 
    'property' : 'original' 
}

console.log(original.property); // 'original'

var clone = original;
clone.property = 'clone';

console.log(original.property); // 'clone' >:(

What about private and public stuff

Having private members with the literal notation is quite a pain in the ass, so let me leave it aside for now. Just think of literal-notated objects as lightweight containers where all members are public. For constructor functions things are easier, thanks to the concept of closure. This is how you set up a constructor function with a couple of private members:

// constructor function
function Website() {

    // private members
    var privateUrl = 'http://www.internalpointers.com';
    var privatePrint = function() {  
        console.log(privateUrl);
    };

    // public members
    this.printUrl = function() {
        privatePrint();
    };
};

var InternalPointers = new Website();
InternalPointers.printUrl();               // 'http://www.internalpointers.com'
InternalPointers.privatePrint();           // TypeError: InternalPointers.privatePrint is not a function
console.log(InternalPointers.privateUrl);  // undefined

Sources

Envato Tuts - The Basics of Object-Oriented JavaScript (link)
Stackoverflow - Should I be using object literals or constructor functions? (link)
Stackoverflow - How to add private variable to this Javascript object literal snippet? (link)
MDN - Object (link)
Douglas Crockford - Private Members in JavaScript (link)

comments
Matt on December 17, 2018 at 21:44
Great, thanks for putting clear explanation together!
Foo on February 19, 2019 at 23:26
What about `Object.create(ObjectLiteral);` as a means to create instances from literal objects? Or IIFE closures oc builder functions which create/init/return object literals, and what about the implications of using prototype with new instantiaton vs builder pattern, and what about cloning/injecting/extending other objects into a closure to simulate prototypical inheritance by sharing members or further prototype mangling. There are more than "Just 2 Ways". There are at the very least, 3.
gamma on December 02, 2019 at 16:36
Sending you some physical claps from Australia.

Started out with JS as a kid and have just tried to pick it up again after learning OOP. This clears so much up for me.
Hey on December 03, 2019 at 12:42
thank you very much. It helped me a lot!
gignu on February 28, 2020 at 22:17
Thx, great article, makes a lot more sense now the whole topic!
Dave Weese on September 05, 2020 at 16:06
Actually you don't have to instantiate separately at all:

var website = new function( param ){ var private_data = param;
... etc } (5);

An arg at the end of the function definition means the function executes (and presumably returns something useful) immediately, thus silly looking IIFE syntax is never needed.

Later you could go : var x = new website(12); and create new instances as needed;

Because you can and generally should return either this, an object literal that defines a specific api or a function that itself returns an object (the most flexible and powerful method), the class syntax in ECMA 6 is redundant and only adds confusion to capability that has been in the language for years.
Jatan on February 25, 2021 at 17:57
Thanks so much for clearing this up. Much love :)