Foundation Of Object-Oriented JavaScript feat. Constructor Function

As everything in Javascript is Objects. So it becomes important to understand what is the thing that is creating the objects, and how we can use it.

Constructor Function

If you are coming from the traditional programming languages, you have heard the concept of the classes. In Javascript, Constructor functions work the same as the classes. You can create as many objects (instance) as you want from the constructor function.

I will refer to the constructor function as a class interchangeably. Also, I have assumed you have the knowledge of closures and scope. If you don't I will highly suggest reading that first.

Example

// Constructor Function
function SoftwareDeveloper(name) {
  this.favoriteLanguage = 'JavaScript'
  this.name = name;
}
const webDeveloper = new SoftwareDeveloper("Nitesh");
console.log(webDeveloper);
// Output: 
// SoftwareDeveloper {favoriteLanguage: "JavaScript", name: "Nitesh", constructor: Object}

I have created the instance known as webDeveloper from the SoftwareDeveloper class.

While defining the constructor function, I have kept the first letter to be capital. But that doesn't mean this is "Constructor function". Developers name constructor functions in CamelCase by convention, it is not enforced by the language.

What does make SoftwareDeveloper() a constructor function is:

  • The use of the new operator to invoke the function.
  • How the function is coded internally. (having this inside)

One last thing that might seem unusual is that this function doesn't seem to return anything. Constructor functions in JavaScript should not have an explicit return value.

The constructor Property

Each time an object is created, a special property is assigned to it under the hood: constructor. Accessing an object's constructor property returns a reference to the constructor function that created that object in the first place.

console.log(webDeveloper.constructor);
// Output:
// ƒ SoftwareDeveloper(name) { this.favoriteLanguage = "JavaScript"; this.name = name; }

this in Constructor Function

We have defined the properties in the constructor function using the this keyword, which states state we want to create a public property.

console.log(webDeveloper);
// Output: 
// SoftwareDeveloper {favoriteLanguage: "JavaScript", name: "Nitesh", constructor: Object}
webDeveloper.name = "Arun";
console.log(webDeveloper);
// Output: 
// SoftwareDeveloper {favoriteLanguage: "JavaScript", name: "Arun", constructor: Object}

How easily, I have modified the name property from the webDeveloper object. Having a public property that can be modified easily in global scope is prone to have bugs in the future.

How To Make Private Properties?

Since JavaScript has no concept of private properties out-of-the-box, there is no special syntax or keyword we can use to protect certain properties from being accessed.

However, we can use scope and closures to create a private state.

The Module Pattern

The Module Pattern is commonly used to create private properties in JavaScript.

// Module Pattern
const developer = (function () {
  let favouriteLanguage = "Javascript";
  return {
    getFavouriteLanguage: () => {
      return favouriteLanguage; // using scope and closure
    },
    setFavouriteLanguage: (name) => {
      favouriteLanguage = name;
    }
  };
})(); // using IIFE

console.log(developer);
// Output:
// {getFavouriteLanguage: ƒ getFavouriteLanguage(), setFavouriteLanguage: ƒ setFavouriteLanguage()}
console.log(developer.getFavouriteLanguage());
// Output: Javascript
developer.setFavouriteLanguage("React");

console.log(developer.getFavouriteLanguage());
// Outout: React

Things To Understand

  • developer is an object that is returned by IIFE
  • favouriteLanguage is a private variable that has no scope outside the IIFE.
  • favouriteLanguage variable is closing over the returned inner function i.e getFavouriteLanguage or setFavouriteLanguage.
  • developer is the only instance we can have. That is we can't create more than one instance.

Keep in mind, that you use the Module Pattern when you want one "version" of an object. If you're looking to instantiate unique objects that follow a certain blueprint, you can always write and invoke a constructor function.

Since JavaScript doesn't have private variables, properties, or methods built-in, we can leverage the Module Pattern to enforce such privacy.

At its core, the Module Pattern leverages scope, closures, and (commonly) IIFE's to not only hide data from external access but also provide a public interface for such data.

Reference

  1. Javascript.info
  2. Udacity OOP course