Reliable and Recognized JavaScript Certification Online #

JavaScript is an object-oriented programming language based on prototypes. It differs from the majority of object-oriented languages that are based on classes.

Class in a typical object-oriented language is a template for creating objects. It consists of fields which hold the state of instances of the class and methods which represent the behavior of instances of the class. Class is an abstract structure rather than specific instance. For example class Shape can represent set of shapes.

Instance is a unique copy of the class that represents an object. For example triangle can be an instance of the class Shape.

Object is an instance of a class. Object has its state represented by fields and behavior represented by methods. For example an object is mentioned earlier triangle.

JavaScript does not have the typical classes on the basis of which objects are created. There are just objects. JavaScript uses prototypes, it means that the prototypical object is a template for the created object. From it a new object takes its initial properties. In addition, each object can define its own properties, both when the object is created and at run time. Any object can be a prototype for another object.

Note: Classes introduced in ECMAScript 2015 did not bring a new object-oriented inheritance model. JavaScript still uses prototype-based inheritance model and classes are only syntactic sugar designed to make the syntax easier to read and use.

 

Classes, reference types and object types

In object-oriented languages, the situation with terminology is simple. There are classes and objects are created as copies of specific classes. In JavaScript the template for the object is a prototype object. Some are looking for an analogy to naming in object-oriented languages. They consider two objects that inherit properties from the same prototype as instances of the same class. They use the name of the constructor as the class name. Others use the term reference type instead of the term class. Another term is the object type and this one is preferred in this guide.

 

Prototypes and Inheritance

Prototypes

The prototype is the object from which another object inherits its properties.

You can create objects using the object literal {} or the constructor function. If you plan to create multiple objects that have the same set of properties, in most cases it will be better to use the constructor. Using the constructor you will avoid repeating the code. However if you define methods directly in the constructor, every object created using this constructor has its own copy of that function object.

Consider following Vehicle constructor:

function Vehicle(make, model) {
    this.make = make;
    this.model = model;
    this.start = function() {
        console.log(this.make + ' ' + this.model + ' starts');
    };
    this.drive = function() {
        console.log(this.make + ' ' + this.model + ' drivess');
    };
    this.stop = function() {
        console.log(this.make + ' ' + this.model + ' stops');
    };
}
var ford = new Vehicle('Ford', 'Focus');
var toyota = new Vehicle('Toyota', 'Corolla');

Here the start(), the drive(), the stop() methods are defined directly in the Vehicle constructor. Every vehicle has its own copy of these function objects.

Better approach is to define methods in the prototype. If a method is defined in the prototype, then all objects created using a given constructor share one function object. It is more efficient in terms of memory. It also allows you to use some object-oriented features described below.

To set up the prototype, use the prototype property of the constructor function. Initially it holds a reference to an empty object.
The Vehicle constructor you can define in the following way:

// here you define the Vehicle constructor
function Vehicle(make, model) {
    this.make = make;
    this.model = model;
}

// in the Vehicle prototype you define properties and methods

// application of all vehicles is transportation:
Vehicle.prototype.application = 'transportation';

// methods of the Vehicle prototype:
Vehicle.prototype.start = function() {
    console.log(this.make + ' ' + this.model + ' starts');
};
Vehicle.prototype.drive = function() {
    console.log(this.make + ' ' + this.model + ' drivess');
};
Vehicle.prototype.stop = function() {
    console.log(this.make + ' ' + this.model + ' stops');
};

Inheritance

Inheritance in JavaScript is the mechanism in which one object is based on another object. The object called “child object” inherits from another object called “parental object” has access to all its properties and methods.

Let’s consider again the Vehicle constructor and create some instances of it:

function Vehicle(make, model) {
    this.make = make;
    this.model = model;
}
Vehicle.prototype.application = 'transportation';
Vehicle.prototype.start = function() {
    console.log(this.make + ' ' + this.model + ' starts');
};
Vehicle.prototype.drive = function() {
    console.log(this.make + ' ' + this.model + ' drives');
};
Vehicle.prototype.stop = function() {
    console.log(this.make + ' ' + this.model + ' stops');
};

// create an instance of the Vehicle
var volkswagen = new Vehicle('Volkswagen', 'Golf');
volkswagen.start(); // Volkswagen Golf starts
volkswagen.drive(); // Volkswagen Golf drives
volkswagen.stop(); // Volkswagen Golf stops

In the example above you create the volkswagen object as the instance of the Vehicle. Then you invoke methods start(), drive() and stop(). However these methods are not defined in the opel instance but in the prototype.
When you call a property or a method on an object and that property or method is not found in this object then inheritance mechanism is used. You check the prototype for that property or method.

Overriding the prototype

All objects that inherit from the same prototype share the same properties and methods. But you are not limited to them in child objects. You can override properties and methods from the prototype by defining them in the object instance. JavaScript always looks for a property in the specific object before it looks in its prototype.

Let’s override the drive() method in an instance of the Vehicle:

var ferrari = new Vehicle('Ferrari', 'LaFerrari');

// here you define custom drive() method for the ferrari object:
ferrari.drive = function() {
    console.log(this.make + ' ' + this.model + ' drives very fast');
};
ferrari.drive(); // Ferrari LaFerrari drives very fast

In the example above you define custom drive() method and then call this method on ferrari object in the normal way.

Dynamic prototypes

If you add a property or a method to a prototype, all objects that inherit from this prototype have access to that property or method. This happens automatically even if you add a property or a method to the prototype after you have already created the object.

var porsche = new Vehicle('Porsche', '911 Turbo');
Vehicle.prototype.accelerate = function() {
    console.log(this.make + ' ' + this.model + ' accelerates');
};
porsche.start();
porsche.drive();
porsche.accelerate(); // Porsche 911 Turbo accelerates

Properties and prototypes

You can use the prototype to set default value for a property for all objects. Then in the object you can use that property from prototype or override it and define it directly in the object.

Vehicle.prototype.light = false;

Vehicle.prototype.turnOnTheLight = function() {
    if (!this.light) {
        this.light = true;
        console.log(this.make + ' ' + this.model + ' - the light is now on');
    } else {
        console.log(this.make + ' ' + this.model + ' - the light is already on');
    }
};

Initially an instance of Vehicle inherits the light property from the prototype and from it takes a default value. When the turnOnTheLight() method is called the instance of Vehicle sets its own value for the light property. It causes that the light property is created in the instance and the light property from prototype is overriden.

To determine if a property is set in the instance or in the prototype use the hasOwnProperty method:

var peugeot = new Vehicle('Peugeot', '308');
console.log(peugeot.hasOwnProperty('light')); // false
peugeot.turnOnTheLight();
console.log(peugeot.hasOwnProperty('light')); // true

Prototypes chain

Your instances rather than from one prototype can inherit properties from more prototypes. You can use a chain of prototypes to create a hierarchy of object types.

So far we defined the Vehicle object type and the Vehicle prototype. Now you may need to create more specialised Vehicle instances, for example vans, all with the same set properties and methods.

If you would need only one instance, then you could simply define new properties and methods in the instance.

In this case the best solution would be to create a new object type like VanVehicle, which instances inherits properties and methods from Vehicle and to define in its constructor specialized properties and methods appropriate for vans.

First we define VanVehicle constructor:

function VanVehicle (make, model, maxPayload) {
    this.make = make;
    this.model = model;
    this.maxPayload = maxPayload;
};

In the second step we define from which prototype inherit VanVehicle instances. We want that instances of the VanVehicle inherit properties and methods from the Vehicle. Therefore we create a new instance of the Vehicle and assign it to the prototype property of the VanVehicle constructor:

VanVehicle.prototype = new Vehicle();

You do not have to pass arguments to the Vehicle constructor. Here only important is which object type is the instance from which you want to inherit properties and methods, not its details.

In the next step we define properties and methods specific for all instances of the VehicleVan and add them to the VanVehicle prototype:

VehicleVan.prototype.type = 'Van';

VanVehicle.prototype.load = function(loadWeight) {
    var addedLoad;
    if (this.currentLoadWeight + loadWeight <= this.maxPayload) {
        addedLoad = loadWeight;
    } else {
        addedLoad = this.maxPayload - this.currentLoadWeight;
    }
    this.currentLoadWeight += addedLoad;
    console.log('Loaded ' + addedLoad + ' kg');
    return addedLoad;
};

VanVehicle.prototype.unload = function(loadWeight) {
    var removedLoad;
    if (this.currentLoadWeight - loadWeight >= 0) {
        removedLoad = loadWeight;
    } else {
        removedLoad = this.currentLoadWeight;
    }
    this.currentLoadWeight -= removedLoad;
    console.log('Unloaded ' + removedLoad + ' kg');
    return removedLoad;
};

Here VanVehicle prototype extends the Vehicle prototype. It inherits properties and methods from the Vehicle prototype and adds its own.

Now you can create an instance of the VanVehicle:

var sprinter = new VanVehicle('Mercedes-Benz', 'Sprinter', 3500);
sprinter.load(4000); // Loaded 3500 kg
sprinter.start(); // Mercedes-Benz Sprinter starts
sprinter.drive(); // Mercedes-Benz Sprinter drives

Calling parent constructor

The VanVehicle constructor repeats in part the same code as the Vehicle constructor. Instead of duplicating the code, you can call the parent constructor, that is the Vehicle constructor using the call() method on the Vehicle function.

function VanVehicle (make, model, maxPayload) {
    Vehicle.call(this, make, model);
    this.maxPayload = maxPayload;
    this.currentLoadWeight = 0;
};

The call() is a build-in method in the function object. The Vehicle.call() invokes the Vehicle function. As the first argument you pass the current instance of the VanVehicle using the this keyword to use it as the this in the Vehicle constructor. The next arguments are arguments for the Vehicle constructor.

Checking the object’s identity

Object instance

You may need to check what instance the object is. To do this use the instanceof operator. It takes as the left operand the object to check and as the right operand the constructor. It checks both the current instance and all objects from which the object inherits.

var peugeot = new Vehicle('Peugeot', '308');
console.log(peugeot instanceof VanVehicle); // false
console.log(peugeot instanceof Vehicle); // true

var sprinter = new VanVehicle('Mercedes-Benz', 'Sprinter', 3500);
console.log(sprinter instanceof VanVehicle); // true
console.log(sprinter instanceof Vehicle); // true

Constructor property

Another possibility is to check what is the object’s constructor, by checking the constructor property:

console.log(peugeot.constructor); // Vehicle()
console.log(sprinter.constructor); // Vehicle()

The constructor property holds a reference to the object’s constructor. By default objects inherit the constructor property from their prototype.

The peugeot object’s constructor property as expected refers to the Vehicle() constructor. It was set correctly by default. However the sprinter’s constructor property also refers to the Vehicle() constructor although it was created by the VanVehicle() constructor. It happens because the default prototype of the VanVehicle() was overridden and set to the Vehicle() instance, to inherit from it:
VanVehicle.prototype = new Vehicle();

That is why inherited constructor property refers to the Vehicle(). This code works correctly and more changes here are not necessary. Just to make the code more clean you can set up explicitly the correct constructor:

VanVehicle.prototype.constructor = VanVehicle;

Now when you create an instance of the VanVehicle(), its constructor property is as expected:

var sprinter = new VanVehicle('Mercedes-Benz', 'Sprinter', 3500);
console.log(sprinter.constructor); // VanVehicle()

No Comments

Reply