Willem van der Veen
Willem van der Veen

Reputation: 36650

Compare Ways of Creating Objects in JS

Doing some literature review about how Objects are created in JS here is what I got so far:

// Using ES6 classes
class Animal1 {
  constructor(name) {
    this.name = name;
  }
}
let fluffy = new Animal1("fluffy");

// Using constructor functions
function Animal2(name) {
  this.name = name;
}
let puppy = new Animal2("puppy");

//  Using Object.create
function createBunny(name) {
  let bunnyObj = Object.create(Object.prototype);
  bunnyObj.name = name;
  return bunnyObj;
}
let bunny = createBunny("bunny");

// Using object literal
function createKitten(name) {
  let kittenObj = {
    name: name
  };
  return kittenObj;
}

let kitten = createKitten("kitten");

console.dir(fluffy);
console.dir(puppy);

console.dir(bunny);
console.dir(kitten);

Where the console.dir got the following output:

javascript objects

I read that ES6 classes are just syntactic sugar which are doing basically the same thing as the constructor function (second way of creating objects in my example)

To me these methods all look the same, since they all create Objects which have 0bject as __proto__ property. Are there any differences in these Objects besides that the objects created with the new keyword are named differently? For instance is there a difference in performance in creating objects in a different manner?

Upvotes: 3

Views: 118

Answers (1)

nem035
nem035

Reputation: 35491

The class constructor does a bit more than the function constructor.

A class is meant to be declarative, safety layer on top of a normal function, restricting you to only use the function for instantiating objects using new and doing inheritance (via the prototype) with the extends and super keywords.

Regular functions can do pretty much everything a class does, except in a more verbose manner and without restrictions. This allows more flexibility but also increases the potential of bugs.

There are a few other notable differences:

  • class declarations are not hoisted while function declarations are

new B() // <-- this is fine cause B is hoisted
function B(){}

new A() // <-- doesn't exist cause A's not hoisted
class A{}

  • class body (basically all the code within a class) is by default executed in strict mode

class A {
  constructor() {
    b = 5; // assigning to a global is an error in strict mode
  }
}

c = 5 // <-- assigning to a global outside of a class is fine since no strict mode
new A()

  • classes have some safety checks such as, for instance, you cannot invoke a class like a regular function (without new):

class A {
  constructor(){}
}

A() // Uncaught TypeError: Class constructor A cannot be invoked without 'new'

All of this additional "syntactic sugar" on top of classes, due to the fact that it does a certain amount of work, would naturally lead to some theoretical performance penalty. That being said, this isn't really significant and shouldn't matter for 99.99% of usages out there.

What really matters about classes is to understand that they are just a prettier layer over existing functionality and that they do not create a new OOP system in JS. It's just (somewhat subjectively) a nicer syntax.

Object.create and object literals allow us to easily instantiate JS objects on the fly. What Object.create does as opposed to using a literal like {}, is that it actually creates a new object whose prototype is the object you give it. Using just {} on the other hand does nothing to prototypes (every {} by default has Object.prototype as its prototype), just creates an object instance.

This means that your given usage of Object.create(Object.prototype) and {} are practically equivalent, where the former is a more verbose version of the latter.

Based concretely on your 4 examples, all 4 objects created are effectively the same.

Upvotes: 4

Related Questions