← go back...

Object creation in JavaScript

When you need a new object in JavaScript you can choose from many options. In this article, I'll try to make sense of all this and I'll propose criteria to choose one option.

This article is a review of current ways to produce a new object in JavaScript

Literal object notation

Also called initializer notation. You can write new objects like this:

const myCar = {
  make: "Ford",
  model: "Mustang",
  year: 1969
};

This will get you an instance just like the one in the previous example that used the Object type's constructor function. Just like that, easy peasy lemon squeezy.

The downside of this (and previous) mechanisms is that you have to manually define all the properties of your objects each time they're created.

Object type constructor

JavaScript has an Object type and you can create new instances of this type using its constructor function like so:

const myCar = new Object();

Then you can add properties to your new object like so:

myCar.make = "Ford";
myCar.model = "Mustang";
myCar.year = 1969;

More info on this here and here.

Using this method you can write quite ambiguous code:

const something = new Object(33);
something.value = 44;

something ==  33  // this is true

So the Object constructor function can receive a value and objects can have properties. This is quite confusing, because it defies the common concept of value equality.

JavaScript uses actual values to compare objects that hold primitive type values like number,string. Non primitive values, in the other hand, are compared by reference.

1 == 1 // always true
{} == {} // always false

If you consider this, the example of new Object(33) is pretty confusing because it behaves as a non-primitive reference type but it gets compared by some value given during its construction. It's quite like doing this:

const a = 1;
a.prop1 = "some value";
a.prop2 = 2; 

This code is only understood by the one who wrote it. This style gets in the way of communicating intent and makes it harder to understand what's going on. There are better alteratives and avoiding this style is encouraged.

Constructor function and new

If there are common properties that you need all the objects of some kind to have you can leverage JavaScript's prototypical inheritance system. There are two true statements in JavaScript which you need to always remind:

Of course, there are some aspects to these truths (where is the fun otherwise?).

* JavaScript syntax lets you write scalars like numbers, booleans and strings and assign them to variables. These scalars are not objects in the sense that they don't have properties and you can't assign them new ones:

// This doesn't make any sense and won't work
1.toString();
1.something = true;

This is not true in other languages like Ruby where you can do this:

65.chr // returns "A"

** There is a common ancestor to all prototypes that has no prototype. You can consider this object as the root for the prototypical system.

A corollary to these rules is that prototypes are objects as well.

JavaScript uses this mechanism to resolve properties in objects. Whenever you access some property of an object like a.prop JavaScript has to decide where the property prop is defined. First it tries to use any property defined in a itself. Then, if it doesn't find it, it searches in its prototype, and in its prototype's prototype, and so on until it finds the property or returns undefined.

After this short introduction to JavaScript prototypical inheritance system, we can introduce constructor functions and the new keyword.

Let's see what we're dealing with an example:

function Comic(id, title, characters) {
  this.id = id;
  this.title = title;
  this.characters = characters;
}

Comic.prototype.getId = function() {
  return this.id;
}

Comic.prototype.getTitle = function() {
  return this.title;
}

Comic.prototype.getCharacters = function() {
  return this.characters;
}

const someComic = new Comic(1, "El señor de los chupetes", ["Súper López", "Tchupón"]);
someComic.getTitle();

Let's dissect this:

You can copy this code and paste it into your browser's JavaScript console to play with it. Try to inspect someComic's properties.

The key for this mechanism to work is using teh keyword new. This changes completely the behaviour of a function's invocation doing some unexpected things along the way.

Using new will bind this to an empty object when calling a function and will assign the function's prototype property as the object's prototype. You can replicate new with the following code:

const someOtherComic = {};
someOtherComic.__proto__ = Comic.prototype;
Comic.call(someOtherComic, 2, "El supergrupo", ["Súper López", "...", "El mago"]);

// This is equivalent to:
const someOtherComic = new Comic(2, "El supergrupo", ["Súper López", "...", "El mago"]);

Quirks & perks

Property declaration

When you assign values to properties of an object, JavaScript places them in the object, not in any of its prototypes. This can be tricky if the property was from any of its prototype objects. Consider this code:

const someComic = new Comic(1, "El señor de los chupetes", ["Súper López", "Tchupón"]);

someComic.getTitle = function() {
  return this.title + ". Hu ha!;
};

If you inspect someComic, you'll see that now it has a getTitle property. The original getTitle inside the object's prototype remains unchanged and other instances of Comic won't have the new one.

Compact syntax

You can produce a more compact syntax writing your constructor functions this way:

function Comic(id, title, characters) {
  this.id = id;
  this.title = title;
  this.characters = characters;
}

Comic.prototype = {
  getId: function() {
    return this.id;
  },
  getTitle: function() {
    return this.title;
  },
  getCharacters: function() {
    return this.characters;
  }
};

Ecmascript2015 class syntax

If you can use Ecmascript2015 you can benefit of a syntactic sugar feature to write your constructor functions and prototypes in a more concise way (and more similar to what you'd use in other languages):

class Comic {
  constructor(id, title, characters) {
    this.id = id;
    this.title = title;
    this.characters = characters;
  }

  getId() {
    return this.id;
  }

  getTitle() {
    return this.title;
  }

  getCharacters() {
    return this.characters;
  }
}

Remember that this is just syntactic sugar and constructor functions and prototypical inheritance is what's going on under the hood.

Object.create function

This function let's you create a new object assigning its prototype object manually:

const birthdayPrototype = {
  isToday() {
    const today = new Date();
    return this.date.getYear() == today.getYear()
        && this.date.getMonth() == today.getMonth()
        && this.date.getDate() == today.getDate();
  }
};

const johnsBirthday = Object.create(birthdayPrototype);

johnsBirthday.date = new Date();
johnsBirthday.isToday() // this is true

johnsBirthday.date = new Date(2016,1,1);
johnsBirthday.isToday() // this is false