Introduction

JavaScript from day one was an OOP language. What exactly is meant by the term 'OOP language' would be covered step-by-step as we progress through this unit, but at the core, it refers to a language that could model a programming problem in terms of objects.

As we have already been able to appreciate in the prior segment of this course, everything in JavaScript is an object, obviously excluding the primitives. This is evident of the fact that JavaScript revolves around the notion of objects — it's based on an object-oriented model.

Amongst some defining characteristics of OOP languages is that they have things called constructors that initialise instances when created.

JavaScript also provides constructors but they are quite different from the constructors we'll encounter in classical OOP languages such as Java, C++, Python, PHP etc.

People coming to JavaScript from these languages would find the notion of constructors in JS quite nebulous. We'll see all these distinctions in detail in this chapter.

This chapter aims to introduce us to the idea of constructors in JavaScript; how to create our very own constructors and thus emulate classes in classical OOP languages; how to instantiate objects using constructors; how constructors actually work in JavaScript internally; and much more.

Let's begin!

What are constructors?

A constructor in JavaScript is nothing more that a function i.e. there is no special syntax that makes a constructor a constructor.

This is in contrast to constructors in classical OOP languages such as Java, C++, Python etc. In these languages, a constructor is part of a class definition, with a special syntax (in Python, it's given by the __init__() method, while in Java, it's given by the name of the class itself) and is usually used to initialise an instance during the instantiation process.

However, in JavaScript, as stated before, there is no notion of a class, hence the idea that a constructor is part of a class becomes meaningless rightaway.

A constructor in JavaScript is technically different than a constructor in a classical OOP language, but theoretically it's quite the same thing:

Let's define is the best we could:

A constructor in JavaScript is a function that is meant to create, and optionally initialise an object.

One thing that's rightaway apparent from the discussion so far is that a constructor is a function. Likewise we should expect all the concepts that apply to functions to apply to constructors as well.

And that is indeed the case, but not for all concepts (we'll see these exceptional cases in this chapter).

Secondly, as the definition suggests, a constructor deals with an object. Hence, when we are talking about a constructor, we are talking about some sort of an object, not of any primitive.

Now, the definition given above for a constructor is a little incomplete. We've skipped on the idea of a prototype, because it's not been explained yet. In the next chapter, when we take a deep dive into prototypes, we'll review this defintion in its complete form.

Anyways, the ECMAScript 5.1 spec, section 4.2.1, itself defines constructors quite nicely. It states that:

Objects in JavaScript may be created via constructors which create objects and then execute code that initialises all or part of them by assigning initial values to their properties.

Moving on, a constructor function is supposed to be invoked with the new keyword. This invocation with new is by far the most crucial thing in the world of JavaScript OOP.

Calling a constructor function with new has the consequence of performing a couple of internal operations before invoking the actual function. These internal operations, as we shall see them later on in this chapter, serve to create an empty object and then call the constructor function with this object provided to it.

With the empty instance in hand, the constructor can add properties and methods to it, and thus, in this way, initialise it.

Note that it's possible to call a constructor function without new — after all it's a function. The same ECMAScript 5.1 spec beautifully states the consequence of doing so:

... Invoking a constructor without using new has consequences that depend on the constructor.

That is, it might just depend on the constructor about what would happen when new is omitted from the constructor's invocation expression.

Sometimes, it might be invalid to call a constructor as a function (i.e. without the new keyword), and sometimes it won't.

For instance, as we have seen in the previous chapters, both the invocations new Array() and Array() are valid and produce the same result. In this case, it's apparent that Array() doesn't impose any restriction on the context of its invocation — it could be called as either: a constructor or an ordinary function.

Conversely, sometimes it might just as equally be invalid to call a function as a constructor. For instance, the Symbol() function can't be called as new Symbol().

Symbols are an advanced concept in JavaScript and likewise we don't explore them in this course. In fact, you wouldn't need them at all for this course. But yes, they are ultimately a useful feature.

To learn more about symbols in JavaScript, refer to Advanced JavaScript — Symbols.

In the following sections, we'll see how to check whether a given function is called as a function or as a constructor.

Creating a constructor

Alright, it's finally time to get working and create a very basic constructor function in JavaScript.

Excited?

As stated before, there is absolutely no syntactic difference between creating a constructor function and creating an ordinary function. Both are created exactly in one of the ways we discussed in the chapter JavaScript Functions Basics.

What distinguishes a constructor from an ordinary function is its body.

An ordinary function won't be creating and initialising objects. (The only exception here is of a factory function, however even a factory a function creates an objects manually and then returns it manually, both of which don't happen with a constructor).

A constructor function implicitly creates an object and then initialises it. Initialising the instance is more than often the case, but it's not mandatory to do so.

A constructor function could be left empty as well. In that case, the way we use it and especially name it in a way that determines that it's a constructor i.e. use it with the new keyword and name it with an uppercase first letter. The constructor's body doesn't exist likewise we can't use it to judge whether the function is a constructor.

In JavaScript, a constructor can be thought of as a class from the OOP terminology.

What is a class in object-oriented programming? At the core, it's something that defines characteristics and behaviour of each of its instances, right?

That quite what a constructor in JavaScript is. It defines characteristics and behaviour of each the objects constructed from it — or better to say, instantiated from it.

There is no class in JavaScript!

An important thing to keep in mind over here is that a constructor in JavaScript is only like a class in a pure class-based OOP language — it's not actually the same thing!

There are two categories of OOP languages: class-based and prototype-based. As mentioned before, Java, C++, Python, PHP fall in the first category i.e. class-based. JavaScript and Self fall in the second category i.e. prototype-based.

You'll often see people saying that a given object o belongs to the class A in JavaScript. The word 'class' here only conveniently implies that the constructor of that object is A(), not that there actually exists a class construct in JavaScript.

The word 'class' is used because its rudimentary to any OOP talk. Devs and other people find it much intuitive to say that an object belongs to some class A instead of saying that it is constructed using the constructor A().

In fact, in many OOP languages, the latter statement i.e. 'an object is constructed using the constructor A()', isn't quite right. In these languages, an object can never be created using a constructor — it's created using a class whose constructor gets called to simply initialise the object after it has been created.

Anyways, if we see it very carefully, saying that an object o belongs to the class A in JavaScript is technically not wrong.

A class in OOP defines characteristics and behaviour related to each of its instances, right? That's exactly the case with A, as stated here.

It is the 'thing' that defines characteristics and behaviour of each of its instances (by virtue of being a constructor function which initialises its instance with various properties and methods, and by virtue of the prototype property on itself.)

In even simpler words, all of the traits of the given object o are nicely defined in A alone, not in any other place. Hence, it's indeed not wrong to say that A is the class of o.

Now, since naming classes in OOP has the convention of uppercasing the first letter, we'll do the same for naming constructors in JavaScript.

Time to consider an example.

Recall the point object we created in the previous to previous JavaScript Objects — Basics chapter, using the object literal syntax. It only had two properties x and y corresponding to the x and y coordinates of the point, respectively.

A point on a graph is a really good starting point to experiment with constructor functions in JavaScript.

Let's create the same kind-of point object, but this time using a constructor.

Before anything else, the first concern we ought to address is what name to give to the constructor?

Well, once again, we'll use the fact that a constructor in JavaScript is quite similar to the idea of a class from the OOP universe. Let's see how to use this fact...

We need to create point objects using our constructor, right? Each of these point object could be said to belong to the class Point, couldn't it? In other words, each object is a Point.

Seems quite reasonable.

Hence, following from the fact that a point belongs to the class Point and that a constructor in JavaScript is analogous to the concept of a class, we'll call the constructor Point. Simple!

OK, so now let's finally define this constructor function Point():

function Point() {
    console.log('A new point created.');
}

For now, we just have a simple log in here. Later on, in this chapter, we'll be adding more stuff in the function's body to initialise the newly-created instance.

Anyways, let's go on and create a Point object.

Creating an object using a constructor is accomplished by invoking the constructor via new, as we already know. A constructor's invocation expression (with new) creates and returns a new instance of the constructor. The overall process of creating the instance is called instantiation.

In the following code, we instantiate a Point object (in line 5) and then log it to see how its represented in the console:

function Point() {
    console.log('A new point created.');
}

var p1 = new Point(); console.log(p1);
A new point created Point {}

In line 5, when the constructor is invoked (new Point()), a handful of things happen.

We'll see all of these things in detail in the next section, but for now let's focus on the fact that amongst these things, the function Point() is called.

This means that its body is executed, which explains the first 'A new point created' log.

Once the function completes, the constructor call returns the instance object created. That is, the whole invocation expression new Point() gets replaced with the created instance object. In the code above, this object is stored in the variable p1. In line 6, we log this instance object.

The second log shown above is taken from the console in Google Chrome. It shows that the name of the constructor of the object is displayed next to the object itself, which is empty in the case above.

Alright, all good uptil now!

We have a Point instance called p1. But wait, it doesn't have an x or y property.

What now?

Well, p1 is an object, right? And we studied in the previous chapter that objects could be assigned new properties at any time just by a simple assignment syntax together with bracket notation or dot notation. That's exactly what we could do here to add the properties x and y to our Point instance.

In the code below, we add the two properties x and y one-by-one to p1, set them to 0, and then finally log them:

function Point() {
    console.log('A new point created.');
}

var p1 = new Point();

p1.x = 0;
p1.y = 0;

console.log(p1);
A new point created Point { x: 0, y: 0 }

Great!

This is a constructor in action.

At this point, you might think that creating a point using a constructor function is quite useless and tiring compared to using an object literal.

Well, yes for now when we haven't used any of the potential of constructors, this whole code is definitely less concise than the one we saw in the chapter JavaScript Objects — Basics. However, once we get to the essence of constructors, it would become apparent that they are way more powerful and capable than the typical and monotonous object literal syntax in cases where we have to create multiple objects all belonging to one particular class (from OOP terminology).

Let's quickly extract some of this potential.

Initialising the instance

Assuming that when a point is created, it's placed on the origin, the following Point() constructor accomplishes this quite nicely:

function Point() {
    this.x = 0;
    this.y = 0;
}

What's happening here is paramount to understand. Time to dive right in...

When Point() is called in line 6, as a constructor, it's quite obvious what's happening in its body i.e. the properties x and y are being assigned on the this object, but what's not that obvious is the value that this resolves to.

What is the object that this points to? If we know the answer to this, making intuition of this Point() constructor would be all peaches and cream — after all, it just adds two properties on a given object.

It turns out that this holds the real potential of OOP in JavaScript. It's what makes it possible to initialise an object upon construction inside the constructor function.

Furthermore, as we shall see in the next chapter, it's what provides a method, otherwise defined on the prototype, with the instance object calling the method. We'll see this idea in the next chapter.

We already have a good working experience of this from the chapter JavaScript Objects — Basics. There, we learnt that this resolves to the object calling a particular function. Yes, indeed that is true, but at least not in the case of a constructor's invocation.

When a constructor function is called (i.e. with new), internally a new empty object is created and then that object assigned to this available inside the function.

Hence, when we are assigning properties to this inside a constructor's body, we are, in effect, initialising the new object being constructed by the constructor's call.

It's not valid to assign a value to this in JavaScript, such as this = {}. Only the internal engine could do this, and it actually does it all the time when entering the execution contexts of given functions.

Coming back to the code above, this means that this inside the constructor points to the Point object ultimately returned from the constructor. Hence, this.x = 0 simply adds a property x to this Point object and sets it to 0, while this.y = 0 adds a property y and sets to 0 as well.

Let's go on and instantiate two Point objects using this constructor:

function Point() {
    this.x = 0;
    this.y = 0;
}

var p1 = new Point();
var p2 = new Point();

console.log(p1);
console.log(p2);
Point { x: 0, y: 0 } Point { x: 0, y: 0 }

Great!

Note that p1 and p2 defined here are two distinct objects. They have the same properties x and y and, at least for now, even the same values for those properties, but they are in no way identical to each other.

In other words, p1 === p2 would return false, as both the objects hold different references.

The idea of objects being stored as references in JavaScript is discussed in JavaScript Objects Basics — Passing by reference.

As you can see here, we just wrote a template kind-of thing for each point object in the form of the constructor Point() once and then using it we created two instances p1 and p2, each having their x and y properties set to 0.

In other words, we don't have to manually go and create each object using the same new literal syntax, merely copied and pasted again and again.

This doesn't have the benefit of reducing repetition in rewriting an object literal for each new object, but also of allowing us to determine whether an arbitrary object is a Point instance or not. This definitely can't be achieved such easily and neatly with an object literal.

Guess what, this is just the beginning of exploring the potential of constructors in JavaScript — there's a lot more to follow.

Now before we explore more of that, let's go over the internals of a constructor's invocation in the next section i.e where does this gets its value from and what other hidden operations get performed behind-the-scenes while we instantiate an instance out of a constructor.

Internals of a constructor

When a constructor function is called in the context of a constructor i.e. with the new keyword, the internal [[Construct]] method of the function object is called.

We learnt in the chapter JavaScript Functions Basics that when a function is called, its internal [[Call]] method is invoked. This happens when the function is called in the context of a function i.e. without the new keyword.

Now, additionally we know that when a function is called in the context of a constructor, its [[Construct]] method is called.

So what happens inside [[Construct]]?

Well, it's quite easy to search for the algorithm executed by [[Construct]] in the latest ECMAScript spec. However, the thing is that the latest spec is quite big and complex and hence with each algorithm assuming knowledge of numerous ideas and internal function calls defined in the spec itself.

One has to be profound of all the primitive ideas discussed in the spec from its very beginning in order to be able to make any sense of given algorithm, like the one executed by the [[Construct]] internal method of functions.

At this stage, or even at an advanced stage as a JavaScript developer, given that we're not an engine developer for the language, all this detail in the spec is of little value to us, at least at this point.

Old ECMAScript specs were better in this regard. Each algorithm was extremely easy to follow and make intuition of. Likewise, we'll refer to an old ECMAScript spec to understand what happens in [[Construct]].

Specifically, we'll be referring to the spec of ECMAScript 5.1. Section 13.2.2, details the algorithm used in the [[Construct]] method of function objects.

We'll abstract away even more details from it that are not really useful for our discussion.

Given a function F, the expression new F() executes the internal [[Construct]] method on F that performs the following steps:

  1. A new empty object is created.
  2. The prototype of this object is set to F.prototype. We'll understand this step much better once we learn about prototypes in the next chapter.
  3. The [[Call]] internal method of the function is executed with its this set to the object created in step 1.
  4. The object created in step 1 is returned.

As you can see, the steps listed above are fairly easy to follow. Even if you were to inspect the actual algorithm as listed in Section 13.2.2 of the spec, you'll find that it's not difficult to make sense of either.

It's just the latest specs starting from the big giant ES6 that really drive the mind crazy with tons and tons of detail.

The most important steps here are 1 and 3.

Step 1 states that calling new F() results in an object being created behind-the-scenes.

Step 3 states that once this object is created (and its prototype set) the function is called just as any other normal JavaScript function is i.e. its internal [[Call]] method is invoked.

However, unlike an ordinary function, the this of a constructor is set to the newly created object. This allows the constructor function's body to initialise the newly-created object.

Practically, this model is an exceptionally intelligent model. A new object is created and then the respective function executed normally as any other function, with its this configured to 'some' object.

This is miraculous. We have an OOP principle being utilised, which is that of a constructor, yet what's powering it is a mere function, which is not an OOP idea.

Isn't this awesome?

Restating it once more, when a function is called as a constructor, its [[Call]] internal method is not invoked directly; rather, it's invoked from within the [[Construct]] internal method.

Now knowing these internals won't make you a completely different JS dev, but yes it would help you understand some other object-related behaviours in JavaScript much better (as we shall explore them in the next chapter) and make you much more confident about the knowledge you have for the language.

With the internals done, let's now resume with extracting more of that potential from our Point() constructor.

Constructor with parameters

In the last code snippet that we saw above, we defined a Point() constructor that created a point object set to the origin with its x and y both assigned the value 0.

Now what if we want to create a point for some other x and/or y coordinates. Well, one way is to beyond and reassign the properties x and/or y.

This is illustrated below:

function Point() {
    this.x = 0;
    this.y = 0;
}

var p1 = new Point();
var p2 = new Point();

console.log(p1);
console.log(p2);
Point { x: 0, y: 0 }
Point { x: 0, y: 0 }

This surely works. But it's redundant and tiring. That is, to change the point to some other set of coordinates or to create a point having different coordinates from the very beginning, we have to write two assignment expressions all manually.

Well, the latter could be solved very easily by taking advantage of the fact that the constructor is just another function. So what, you ask?

Hmm. Think of it.

We could set up the constructor to accpe the x and y coordinates of the point to-be-created as arguments.

Consider the code below:

function Point() {
    this.x = 0;
    this.y = 0;
}

var p1 = new Point();
var p2 = new Point();

console.log(p1);
console.log(p2);
Point { x: 0, y: 0 }
Point { x: 0, y: 0 }

With this Point() constructor in place we could now very conveniently create a Point object to represent any point on a graph from the very beginning of its inception, not just a point on the origin.

Let's go on and actually create a couple of points:

It is all amazing!

Although this constructor works flawlessly there's a slight betterment oppurtunity in it that we could, and preferably should, fill.

Let's see that...

Currently, if we want to create a bunch of points pointing to the origin, we have to manually pass in the arguments 0 and 0 to the constructor's invocation i.e. new Point(0, 0). Given the fact that the origin is a common location, we could simplify the work at our end when creating points on the origin.

That is by allowing the arguments x and y to be omitted and in that case taken to be 0. In other words, we could make the parameters x and y optional and default them to 0, if omitted.

Let's do this using ES6 default-valued parameters:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;
}

var p1 = new Point();
console.log(p1);

var p2 = new Point(-2, 1);
console.log(p2);
Point { x: 0, y: 0 }
Point { x: -2, y: 1 }

Now our constructor is quite flexible. If we just write new Point(), that's effectively the same as new Point(0, 0).

ES6 default-valued parameters aren't supported, as with all ES6 features, on old browser. Hence, to get the code above to work properly on these old browsers, we have to use the ?:-style check.

Shown below is the code:

function Point(x, y) {
    this.x = x !== undefined ? x : 0;
    this.y = y !== undefined ? y : 0;
}

var p1 = new Point();
console.log(p1);

var p2 = new Point(-2, 1);
console.log(p2);
Point { x: 0, y: 0 }
Point { x: -2, y: 1 }

The question is: which one of these two ways of enabling default-valued parameters should we use?

Well, if we are 100% sure that the environment where our JavaScript program would run supports ES6, then without any second thought, we should go for ES6 default-valued parameters.

Otherwise, we should definitely use ?: or an if..else check if we want to support older browsers.

Adding methods

So far, we are on the right track to building our Point() constructor from scratch with the desired functionalities for creating a point object.

When called without any arguments, it creates a Point object situated at the origin. Otherwise, it creates a Point object situated at the given set of coordinates (provided as args). Simple enough.

This parameter version of our Point() constructor has surely kept us from having to manually assign values to the x and y properties to a Point instance after it is created, if we want to create a point located at some place other than the origin, to start with.

However, one thing is stil not addressed. That is when we want to change the coordinates of a given point after it has been created.

For example, suppose that we create a new point object via the expression new Point(0, 2) and then save the returned instance in the variable p1. Now what if we want to change this point to the set of coordinates (3, 6)?

Well, given the setup we have right now, there's only one way to do this, as shown below:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;
}

var p1 = new Point(-2, 8);

// reposition p1 to (1, 5)
p1.x = 1;
p1.y = 5;

console.log(p1);
Point { x: 1, y: 5 }

We have to manually change the respective properties one-by-one.

Once again, this manual work is tiring. The good news is that it could be prevented as well.

But how?

Well, recall the fact that inside a constructor, we initialise the instance being created by adding properties to it. Methods are simply special cases of properties so we could add them to the instance as well and thus describe its behaviour.

In our case, we could define a setTo() method that serves to reposition a point to another set of coordinates. It takes in two args x and y, and then assigns them to the x and y properties of the Point object, respectively.

With this method, we would no longer need to manually write assignment statements to change the x and y properties of a given point.

In the code below, we define this method:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    }
}

Let's go on and do the same point repositioning here that we did in the code above:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    }
}

var p1 = new Point(-2, 8);

// reposition p1 to (1, 5)
p1.setTo(1, 5);

console.log(p1);
Point { x: 1, y: 5, setTo: f }

As is clear, this time we don't have to go through the manual work of reassign both the properties x and y on the object p1. The repositioning is only one call away.

Good!

Although this code works absolutely fine, there is a slight problem with it. This problem is discussed in the next section.

Problem with constructors

Any code that is written inside a constructor's definition is executed for each instantiated object. In the case of mere properties that have to be maintained for each instance, this isn't a problem.

After all, each instance usually has distinct properties. But behaviour are usually not local to instances.

For instance, there might be tons of different Tesla Model S cars on earth right now, each with different properties, such as the name of the owner, the body color, etc, but they all have the same internal mechanism of braking, right?

In simple words, adding methods to instances from within the constructor in the way we add properties is usually not a good idea, given that the methods perform the same action for all instances.

But why?

Why is it so that adding methods isn't a good idea? What's the problem?

Let's see it...

Consider the latest definition of Point() from the last code snippet shown above:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    }
}

Let's create two instances p1 and p2 out of this Point() constructor. Each of these instances has a setTo() method as we already know, which is confirmed by the logs made here:

function Point(x = 0, y = 0) {
    /* ... */
}

var p1 = new Point(-2, 8);
var p2 = new Point();

console.log(typeof p1.setTo);
console.log(typeof p2.setTo);
function function

Now, let's go on and compare the setTo() method of p1 with that of p2 to see whether they both are the same:

p1.setTo === p2.setTo
false

No, they ain't the same!

p1 has its own setTo() method while p2 has its own setTo() method. Both these methods perform exactly the same task, yet they ain't the same. This is a problem.

Our code is not DRY (Don't Repeat Yourself).

We are merely repeating stuff. Note that this repetition is not in terms of actual code — verbally, there isn't stuff that is being repeated (at least for the sake of argument). Rather, the repetition is in terms of the way the code is creating stuff in memory.

To be more precise, the code is creating a separate setTo() method for each instance.

  1. Storing these different function objects assigned to setTo obviously consumes memory.
  2. Storing keys on an object consumes memory as well. Here, we are referring to the key 'setTo'.
  3. Storing references (i.e. addresses) to function objects also takes up memory.

In short, the code above is consuming quite a lot of memory without any purpose. To put it other way, the code above is simply wasting memory.

For now, that's not a significant amount of wastage. But if we were to continue on with this memory-wasting coding practice to make intricately complex JavaScript applications, we would eventually end up with a performance bottleneck, due to high memory usage.

In complex applications, even the smallest of sensible optimizations matter.

So this is the problem with constructors — in most cases, they shouldn't be used to define instance methods.

One obvious remedy to this is to create the function objects in the global scope and then create methods on the instance by means of passing a reference to these global functions.

Let's try this with our code:

function pointSetTo(x, y) {
    this.x = x;
    this.y = y;    
}

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.setTo = pointSetTo;
}

var p1 = new Point(-2, 8);
var p2 = new Point();

console.log(p1.setTo === p2.setTo);
true

We have taken the definition of the function assigned to setTo outside the Point() constructor. In this way, it's not re-created each time Point() is called. The log made also shows that both p1.setTo and p2.setTo point to the same function object.

In terms of memory consumption, this is definitely a better choice.

But it doesn't solve all of the problems...

Firsly, we are still defining setTo on each instance, even though there is no need to. Ideally, stuff defined separately for each instance of a constructor should define traits of the instance (that are usually different for each instance) and in this way define its state. So that's problem 1.

Secondly, we have effectively lost encapsulation of the stuff related to a Point object within the Point() constructor. That is, we are now filling up the global scope with stuff that ideally should've been somehow defined as part of the Point class only, and not anywhere else.

Imagine if we had five such global functions to be ultimately assigned to properties of a Point instance inside the Point() constructor. Shown below is a very simple illustration:

function pointFunction1() { /* ... */ }

function pointFunction2() { /* ... */ }

function pointFunction3() { /* ... */ }

function pointFunction4() { /* ... */ }

function pointFunction5() { /* ... */ }


function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.method1 = pointFunction1;
    this.method2 = pointFunction2;
    this.method3 = pointFunction3;
    this.method4 = pointFunction4;
    this.method5 = pointFunction5;
}

This is quite a global mess, isn't it?

Plus, if the program defined some other global functions (in addition to these 5 functions) not related to the Point class in any way, then it would've been even more of a mess.

Now, someone could go on and argue that to prevent global namespace pollution, we could wrap an IIFE around the whole code defining the Point() constructor and its related functions.

This is possible, but much more headache than a solution. A solution ought to be one that solves a problem without imposing hundreds of problems of its own. Let's see the problems with using an IIFE here.

The code above, as encapsulated inside an IIFE, is demonstrated below:

var Point;

(function() {
    function pointFunction1() { /* ... */ }

    function pointFunction2() { /* ... */ }

    function pointFunction3() { /* ... */ }

    function pointFunction4() { /* ... */ }

    function pointFunction5() { /* ... */ }


    Point = function(x = 0, y = 0) {
        this.x = x;
        this.y = y;

        this.method1 = pointFunction1;
        this.method2 = pointFunction2;
        this.method3 = pointFunction3;
        this.method4 = pointFunction4;
        this.method5 = pointFunction5;
    }
})();

First of all, we have to make sure that Point is declared outside the IIFE (line 1) in order to be accessible in the global scope. Secondly, we have to change the Point function declaration to a function expression (line 15) and assign that to the variable Point.

Moreover, we also have to increase the indentation of the code inside the IIFE.

But still, we are creating separate properties method1, method2, ..., on each Point instance, even though they all point to the exact same function objects internally.

Overall, the code looks quite ugly and unmaintainable. If we look at the bigger picture from a distant view, everything is senseless.

So an IIFE is clearly not a solution to our global-scope-pollution problem.

Another way could be to create an object literal holding all the functions that define behaviour for a Point object:

var pointMethods = {

    function1: function() { /* ... */ },

    function2: function() { /* ... */ },

    function3: function() { /* ... */ },

    function4: function() { /* ... */ },

    function5: function() { /* ... */ }

}

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.method1 = pointMethods.function1;
    this.method2 = pointMethods.function2;
    this.method3 = pointMethods.function3;
    this.method4 = pointMethods.function4;
    this.method5 = pointMethods.function5;
}

But once again, we are creating an extra object pointMethods here without any purpose at all, and shifting the logic of Points (i.e. the functions function1, function2, ...) out from the Point constructor.

Moreover, as you can see, we are again and again referring to pointMethods in lines 19 - 23, which seems quite repetitive. Overall, the code looks even more uglier than the previous one.

So, using an object literal isn't a solution either.

Oh, wait! Let's put all the functions function1, function2, ..., on the Point function object itself. After all, it's an object as well.

This is demonstrated below:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.method1 = Point.function1;
    this.method2 = Point.function2;
    this.method3 = Point.function3;
    this.method4 = Point.function4;
    this.method5 = Point.function5;
}

Point.function1 = function() { /* ... */ };

Point.function2 = function() { /* ... */ };

Point.function3 = function() { /* ... */ };

Point.function4 = function() { /* ... */ };

Point.function5 = function() { /* ... */ };

Compared to creating a new object literal to store all the given function objects, this way is slightly better in that we don't have to introduce a new identifier into the environment where Point exists i.e. we don't have to create a separate object like pointMethods.

However, regardless of any of these ways — of using an IIFE, or an object literal, or the Point constructor function itself to prevent global namespace pollution — we still haven't solve one long-lasting problem:

That is, each instance still defines separate method1, method2, ..., method5 properties on itself that all together define behaviour of the instance.

As stated before, behaviour of instances are common to all instances and likewise methods (that define the behaviour) must not be created for each instance object separately.

To boil all of this discussion down, defining methods inside a constructor function's definition is, in most cases, NOT a good idea.

But, then what's the good idea? How to define methods for the instances of a class?

There's one and only one answer to this — prototypes. We shall discover them in the next chapter.

The instanceof operator

Recall that we said that creating objects using literals vs. creating them using constructor functions has the difference that we could easily distinguish between objects created using the constructor and those created using some other way.

It's now time to see how to do this...

The instanceof operator as the name suggests tells us whether a given object is an instance of a given constructor (which we could also think of as a class, remember?).

It's a binary operator as might already be apparent from its definition. Syntactically, here's how to use it:

obj instanceof F

obj can be any valid JavaScript value while F must be a constructor function. This expression returns true if obj is an instance of F, or otherwise false.

Let's try running it on our Point objects p1 and p2:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    };
}

var p1 = new Point(-2, 8);
var p2 = new Point();

console.log('p1 instanceof Point:', p1 instanceof Point);
console.log('p2 instanceof Point:', p2 instanceof Point);
p1 instanceof Point: true p2 instanceof Point: true

As can be seen, p1 and p2, as inspected using instanceof, both return true.

Let's test instanceof on some arbitrary object:

{ x: 0, y: 0 } instanceof Point
true
{} instanceof Point
true

As expected, we get false returned in both cases, since { x: 0, y: 0 } is not a Point instance, and neither is {}.

Note that as stated before, instanceof returns true only when the given object is an instance of the given constructor, not when the given object is the given constructor itself.

That is Point instanceof Point won't return true:

Point instanceof Point
false

To test whether a given object is a given constructor, we could very simply compare it with that constructor using ==, quite obviously.

Point === Point
true

The constructor property

When an instance is created using a constructor, there is a constructor property available on the instance. This points to the constructor function used to create the object.

To mention it precisely, when an instance i is created from a given constructor F, its prototype object is set to the prototype property of the constructor function F. This prototype object, that is common to all instances of F, contains a constructor property that points back to the constructor function.

Once again, we'll understand this much better once we are done with prototypes.

Anyways, let's bring into consideration our old Point() constructor function and an instance p1 constructed out of it:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    };
}

var p1 = new Point(-2, 8);

We'll see what does p1.constructor have to return:

p1.constructor
ƒ Point(x = 0, y = 0) { ... }

As can be seen, p1.constructor returns back the constructor of p1 i.e. the Point() constructor.

This is exactly the same constructor Point(), likewise we could use it to create another instance, although it's not sensible to do so if we have direct access to the constructor (it is clearly less readable).

An illustration is shown below:

new p1.constructor(2, 5)
Point { x: 2, y: 5, setTo: ƒ }
The constructor property is non-enumerable i.e. it doesn't show up in a for...in loop. We learnt about property enumerability in the previous chapter JavaScript Objects — Property Attributes.

Subclass emulation using constructors

Back in the OOP Introduction chapter, we learnt that a subclass is a class that inherits from a given superclass. For instance, the Cat class is a subclass of the Animal class. Every Cat is an Animal.

In classical OOP languages, we could create classes that inherit from given classes. The constructor method in the subclasses could call the constructor methods of the superclasses.

In JavaScript, this idea of calling the parent class' constructor from within the constructor of the subclass is possible, but not as straightforward as it might seem.

Let's first see what's the problem in going the straightforward way.

Consider the task of creating a shape drawing application in JavaScript. At the forefront, this is a big challenge to undertake. It requires us to know about a ton of things — a ton literally means a 'ton'. Obviously, at this stage, we couldn't create this. But, at least, we could make some things to be ultimately used in the application.

Let's assume that each shape is denoted by the Shape class. A Shape could have a fill color given as a hexadecimal value (including the hash symbol), and a position on the canvas (the main drawing area) given as two properties x and y representing the x and y coordinates on the canvas, respectively (in addition to numerous other properties).

The most abstracted Shape constructor would look something like this:

function Shape(fill, x, y) {
    this.fill = fill;
    this.x = x;
    this.y = y;
}

On its own, the Shape class doesn't seem very useful. And, indeed, it isn't. It doesn't define the geometry of the underlying shape.

Since there can be multiple kinds of shapes, such as rectangles, circles, triangles, polygons, stars, and so on, and each of these would have a different geometry, it seems sensible to create subclasses of Shape to represent these shapes in the application.

The subclass we'll construct right now is Rect to denote rectangles.

Rect could have a length property and a height property to determine the area spanned by the rectangle.

Let's create this Rect class as well:

function Rect(length, height) {
    this.length = length;
    this.height = height;
}

Now, as we said before, Rect is a subclass of Shape. This simply means that every Rect is a Shape as well. Consequently, every Rect object must have all the properties a Shape object has.

Let's go on and define those properties in the Rect() constructor:

function Rect(length, height, fill, x, y) {
    // initialise Shape properties
    this.fill = fill;
    this.x = x;
    this.y = y;

    this.length = length;
    this.height = height;
}

Note that we had to modify the parameter list of Rect here as well — previously, it had two parameters; now it has five of them.

But hey, wait. Isn't this repetition of code? We are redefining assignment statements for a Shape object again inside the Rect() constructor.

Yes, you guessed it right.

It sure is repetition of code and so we should avoid it. We could do much better than this code.

One straightforward solution that might come in the mind of the novice developer (this is not you because you are quite much aware of many aspects of JavaScript at this point in this course) is to call the Shape() constructor from within the Rect() constructor as new Shape().

The thinking of calling Shape() is perfectly alright — after all, to prevent repeating the code written inside Shape(), we ought to call it. However, this invocation couldn't be a straightforward invocation with new.

Let's see the problem...

Below we call the Shape() constructor from within Rect() in line 3, passing it all the desired arguments:

function Rect(length, height, fill, x, y) {
    // initialise this Shape
    new Shape(fill, x, y);

    this.length = length;
    this.height = height;
}

Time to test this code. First, we'll instantiate a Rect instance by providing some dummy arguments to Rect() and then log each of the five properties of this instance one-by-one:

var r1 = new Rect(20, 10, '#000', 0, 0)
undefined
r1.length
20
r1.height
10
r1.fill
undefined
r1.x
undefined
r1.y
undefined

Can you see the problem here?

The object doesn't seem to have any of the properties x, y or fill. length and height, though, are present. One thing is clear — there is some logical error in the code above.

Now before we go on and debug that error, take a break for a few seconds and think about the reason of this logical problem.

Why doesn't the r1 object have properties of a Shape?
The answer has to do something with functions.

Alright, it's answer time...

In the code above, when we call new Shape(), a new object is created and the properties fill, x and y added to that object. This is just the problem.

The Shape() constructor's invocation as a constructor simply creates a new binding for this, that is a new Shape instance. This instance is what receives all the initialisation code of Shape().

Even if we were to assign Shape to this.parent inside Rect() and then go like new this.parent(), there would be absolutely no difference in the final result — the properties fill, x and y would be undefined on the Rect instance.

That's because a constructor's invocation creates its own binding for this. In layman terms, a constructor call hijacks the function's this.

Any solutions?

Well, we have basically two ways out of this:

One is already shown above, though in a slightly different way. It is to define a method on the instance inside Rect() and point it to the Shape() constructor, and then call this method. This would semantically set this of the method (i.e. the Shape() function) to the calling object (i.e. the Rect instance).

Shown below is a demonstration:

function Rect(length, height, fill, x, y) {
    // initialise this Shape
    this.parent = Shape;
    this.parent(fill, x, y);

    this.length = length;
    this.height = height;
}

As before, let's test this:

var r1 = new Rect(20, 10, '#000', 0, 0)
undefined
r1.length
20
r1.height
10
r1.fill
'#000'
r1.x
0
r1.y
0

Yeah, it works!

The other way is to use the power of the function method call() to configure this for the constructor function.

This is much better than the previous way, as we don't have to create a new property (parent in the case above) on the instance to hold the parent constructor.

Remember how to use the call() function method? We covered it in the chapter JavaScript Function Methods — call().

The first argument to call() specifies the value to be used as this in the calling function; the rest of the args to call() specify args to be passed into the calling function.

Therefore, in our case, first of all we need to pass in this of the Rect() constructor to the invocation Shape.call() and then pass in the arguments x, y and fill.

Simple?

Let's implement this:

function Rect(length, height, fill, x, y) {
    // initialise this Shape
    Shape.call(this, fill, x, y);

    this.length = length;
    this.height = height;
}

Time for the testing:

var r1 = new Rect(20, 10, '#000', 0, 0)
undefined
r1.length
20
r1.height
10
r1.fill
'#000'
r1.x
0
r1.y
0

Amazing!

You'll find this second way used very frequently out there — this is because it's the simplest way to emulate parent class constructor invocation in JavaScript.

It's good to be aware of the first way in case you ever encounter a script that uses it and not the call() function method.

So, at this point, we have successfully prevented repetition of the code within the parent constructor Shape() by reusing it inside Rect().

This technique is commonly referred to as constructor stealing, or constructor borrowing, following from the fact that we merely steal the constructor's code to be used in the context of another constructor.

Static methods

In the OOP world, given a popularity/method it could either be an instance property/method or a static property/method.

Instance property/method is one that is directly accessible on an instance. In contrast to this, a static property/method is one that is directly accessible on the underlying class — there's no way to access it directly via an instance of the class.

Static properties/methods are used when some characteristics/behaviour ought to be defined that aren't related to instances, but rather related to the class.

For example, the sort() array method is not a static method — it's an instance method. Why?

Because we sort arrays right? On the contrary, the isArray() method is a static method of the Array class. This is because it isn't meant to be run on an Array instance (logically that would've been senseless as if isArray() was an instance method it would've always returned true).

The method isArray() is meant to take any arbitrary argument and determine if that's an Array or not.

Note that this method Array.isArray() could've been provided as a global function (directly accessible on window as window.isArray() or simply as isArray()). The benefit of adding it to the Array class is that we keep from unnecessarily overcrowding the global scope, and put all array-related functionality nicely within the Array class.

To even better understand this concept, let's add a static method to our Point class that determines the distance between two points each given as an array of two elements x and y.

The most important thing to note here is that by the static method, we don't enforce the points to be represented as Point objects. They could be two-element arrays or any other sequence whose first and second items given the x and y coordinates of the underlying point, respectively.

Consider the following code:

function Point(x = 0, y = 0) {
    /* ... */
}
                
Point.distance = function(p1, p2) {
    // calculate distance between p1 and p2
    return Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2);
}


var p1 = [0, 0];
var p2 = [3, 4];

console.log(Point.distance(p1, p2));
5

See how we are entertaining two sequences representing points and not enforcing them to be Point objects first.

Stating it once again, this distance() method on Point could've been a distance() function in the global scope. The benefit of using Point is that it prevents pollution of the global scope and nicely keeps everything related to points within Point.

Great!

Calling constructors as functions

In the previous chapters, we've seen it numerous times that a predefined constructor is called as a function, yet it works exactly like a constructor.

For instance, if we call Array() or new Array(), we get exactly the same thing returned back.

How could this be accomplished for our Point() constructor?

Well, if you think about it, it's quite simple: if the constructor is invoked as a function, we reinvoke it (i.e. recursively call from itself) as a constructor (i.e. using new). Otherwise, it means that it was invoked as a constructor and so, likewise, we proceed with the initialisation code for the instance created.

But how do we check whether a constructor is called as an ordinary function or vice versa?

Hmm. This is a good question.

There are mainly two ways to accomplish this:

  1. Use the ES6-style expression new.target
  2. Use the instanceof operator

We start by considering the latter.

We'll take the example of our very own constructor Point().

First let's reason about how could instanceof be used.

If Point() is called as a constructor, what would its this resolve to? We just learnt about this in the sections above. It would resolve to the Point instance created.

On the otherhand, if Point() is called as a function or as a method then what would this resolve to? Well, if it's called as a function, this would clearly resolve to the global object window. Otherwise, if it's called as a method, this would resolve to the calling object.

Simple.

This discussion has already laid the solution. Let's see it...

The thing is that we could use instanceof to check whether this inside Point() is an instance of the Point constructor. If this returns true, this means that we are on the right track i.e. Point() is called as a constructor.

Otherwise, it means that Point() is called as a function/method (i.e. in a non-constructor context).

Easy? Let's finally implement this.

In the code below, we throw an error if the Point constructor is called as a function, or else proceed with the initialisations of the instance.

function Point(x = 0, y = 0) {
    // if called as a function, throw an error
    if (!(this instanceof Point))
        throw new Error('Illegal function call Point().')

    // otherwise, proceed as usual
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    }
}

Let's try this:

new Point(2, 3)
Point { x: 2, y: 3, setTo: ƒ }
Point(2, 3)
Uncaught Error: Illegal function call Point(). at Point (<anonymous>:4:13) at <anonymous>:1:1

As you can see, the second prompt here throws an error, since it calls Point() without new.

Note that instead of throwing an error, we could also configure Point() to make the correct call itself. That is, when we call Point() as a function, the function could call itself as new Point().

This is accomplished below:

function Point(x = 0, y = 0) {
    // if called as a function,
    // recall as constructor and return the instance
    if (!(this instanceof Point))
        return new Point(x, y);

    // otherwise, proceed as usual
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    }
}

Let's try this the same way we tried the constructor above:

new Point(2, 3)
Point { x: 2, y: 3, setTo: ƒ }
Point(2, 3)
Point { x: 2, y: 3, setTo: ƒ }

Now, Point() vs. new Point() holds absolutely no distinction in terms of the final return value.