Function constructors are the most popular way to create objects in Javascript. Classes can also used, however,  classes are nothing but just a syntactic sugar on top of function constructors.

Creating Objects Using a Function Constructor

Here's how we create objects in Javascript using a function constructor:

function Car(brand, model) {
  this.brand = brand;
  this.model = model;
}

const car = new Car('Ford', 'Fiesta');

Now, suppose we need a method that returns us the full car name like 'Ford Fiesta'. We can add a method to the function constructor - getCar

function Car(brand, model) {
  this.brand = brand;
  this.model = model;
  this.getCar = function() { return `${this.brand} ${this.model}` };
}

const car = new Car('Ford', 'Fiesta');
console.log(car.getCar()); // Prints Ford Fiesta

All good right?

Now, there are thousands of car models that exist in the world. We need to be able to create objects for all of those, not just a single car.

function Car(brand, model) {
  this.brand = brand;
  this.model = model;
  this.getCar = function() { return `${this.brand} ${this.model}` };
}

const cars =[];
cars.push(new Car('Ford', 'Fiesta'));
cars.push(new Car('Ford', 'Fusion'));
cars.push(new Car('Ford', 'Ranger'));
cars.push(new Car('Honda', 'Accord'));
cars.push(new Car('Honda', 'Civic'));
// ....
// .... Thousands of objects
// ....


cars.forEach(car => console.log(car.getCar()));

Can we optimise the  code above to take into account existence of thousands of cars?

How to optimise?

When we create methods within function constructors, every object gets a separate copy of the method. So let's say, the getCar method adds 1KB of memory to an instance. 1000 such instances will need 1000KB ~ 1MB.

There's a way in Javascript we can avoid that - Prototypes to the rescue. We need to define the method just once on the prototype and it would be available to use for any number of objects we create using the function constructor.

See the code below:

function Car(brand, model) {
  this.brand = brand;
  this.model = model;
}

Car.prototype.getCar = function() {
  return `${this.brand} ${this.model}`
};

const cars =[];
cars.push(new Car('Ford', 'Fiesta'));
cars.push(new Car('Ford', 'Fusion'));
cars.push(new Car('Ford', 'Ranger'));
cars.push(new Car('Honda', 'Accord'));
cars.push(new Car('Honda', 'Civic'));
// ....
// .... Thousands of objects
// ....


cars.forEach(car => console.log(car.getCar()));

Just a single copy of getCar defined once, will be available to all objects. We saved 999KB - huge optimisation.

This is something Javascript engines would be optimising for already, but we as developers should not be dependent on that.

I hope this was useful. For more tips on optimisations, don't forget to subscribe below.