Douglas Crockford described JavaScript as the world’s most misunderstood language. Like many developers, when I started learning JavaScript, to me also, this was not a “proper” language. But I quickly understood that JavaScript comes with a rich system of object-oriented programming.
There are many concepts that makes JavaScript unique, but prototype model is definitely the most important one and it creates many confusions. So having a clear understanding of prototype model is very important. And in this post, I would like to explain the concept of prototype based programming in JavaScript.
The prototype based programming is a very easy to understand concept, but the source of confusion is the syntax. When a new developer looks at the JavaScript code and sees new, class or constructor it makes them think that object instantiation works the same way as other languages. But in reality, they are nothing more than syntactic sugar in JavaScript. Behind the scenes, things are working in different way. So it is very important to have a clear understanding how things works which will help you to predict their behavior.
Class Based Language
- class – the interface which defines the properties and methods.
- entities – instantiations of the class (objects)
An instance is exact same copy of the class, you cannot dynamically add/remove properties/methods from the instance as declared in the class. You can definitely override them, but then it comes to inheritance. In this model, one instance belongs to one class only. Of course, those classes can also inherit from others. This is how Class Bases language works.
Prototype Based Language
//Property name at declaration
var student = {
"name":"Sudipta Deb"
}
//This will throw an error as the function is not yet defined.
student.sayFullName();
//Let's add the function as runtime
student.sayFullName = function(){
console.log('FullName: ' + this.name);
}
//This time it will print the fullname
student.sayFullName();
Check example here. Initially the method sayFullName() was declared, but it was added dynamically later.
Understand Prototype Object
- A prototype is an object which is used as template from which all new objects will get their properties.
- Any object can be used as a prototype for another object and share the properties with that object.
- The object can override the inherited methods/properties, but it will not impact the prototype.
- The prototype can change it’s methods/properties or add new ones, which will impact the objects which was created from the same prototype.
So basically we create copies from one object and then all copies will move with their own life. The new object will have access to all the methods/properties of the prototype as long as they are not overridden. Even if there is any method/property being added to the prototype class after the object creation, object will still have access to those newly added method/property. Any changes in the object will not impact prototype, but any change in prototype will impact all objects. This is the core of prototype based programming. Let’s understand this below example.
Vehicle Example
function Vehicle(){
this.manufacturers = '';
this.year = '';
}
//Definition of Vehicle Object
function Vehicle(){
this.manufacturers = '';
this.year = '';
}
//Definition of Bus Object
function Bus(){
Vehicle.call(this);
this.routeNumber ='';
}
Bus.prototype = Object.create(Vehicle);
Bus.prototype.constructor = Bus;
//Definition of Car Object
function Car(){
Vehicle.call(this);
this.type = '';
}
Car.prototype = Object.create(Vehicle);
Car.prototype.constructor = Car;
//Definition of Vehicle Object
function Vehicle(){
this.manufacturers = '';
this.year = '';
}
//Definition of Bus Object
function Bus(){
Vehicle.call(this);
this.routeNumber ='';
}
Bus.prototype = Object.create(Vehicle);
Bus.prototype.constructor = Bus;
//Definition of Car Object
function Car(){
Vehicle.call(this);
this.type = '';
}
Car.prototype = Object.create(Vehicle);
Car.prototype.constructor = Car;
//Definition of Gasolin Car
function GasolinCar(){
Car.call(this);
this.mileage = '';
}
GasolinCar.prototype = Object.create(Car);
GasolinCar.prototype.constructor = GasolinCar;
//Definition of Electric Car
function ElectricCar(){
Car.call(this);
this.batteryCapacity = '';
}
ElectricCar.prototype = Object.create(Car);
ElectricCar.prototype.constructor = ElectricCar;
The new Operator
//Let's create new objects now
var teslaGasolinCar = new GasolinCar();
teslaGasolinCar.mileage = 12;
teslaGasolinCar.type = 'Car';
teslaGasolinCar.manufacturers = "Tesla";
teslaGasolinCar.year = 2018;
console.log('Mileage:' + teslaGasolinCar.mileage);
console.log('Type:' + teslaGasolinCar.type);
console.log('Manufacturer:' + teslaGasolinCar.manufacturers);
console.log('Year: ' + teslaGasolinCar.year);
console.log('__proto__: ');
console.log(teslaGasolinCar.__proto__);
console.log('prototype: ');
onsole.log(teslaGasolinCar.prototype);
- A generic object is created.
- The __proto__ is set to GasolinCar.prototype
- Finally GasolinCar function is called, with this representing the newly created object
Create Multiple Objects with new Operator
//Definition of Vehicle Object
function Vehicle(){
this.manufacturers = '';
this.year = '';
}
//Definition of Bus Object
function Bus(){
Vehicle.call(this);
this.routeNumber ='';
}
Bus.prototype = Object.create(Vehicle);
Bus.prototype.constructor = Bus;
//Definition of Car Object
function Car(){
Vehicle.call(this);
this.type = '';
}
Car.prototype = Object.create(Vehicle);
Car.prototype.constructor = Car;
//Definition of Gasolin Car
function GasolinCar(){
Car.call(this);
this.mileage = '';
}
GasolinCar.prototype = Object.create(Car);
GasolinCar.prototype.constructor = GasolinCar;
//Definition of Electric Car
function ElectricCar(){
Car.call(this);
this.batteryCapacity = '';
}
ElectricCar.prototype = Object.create(Car);
ElectricCar.prototype.constructor = ElectricCar;
//Let's create Tesla objects
var teslaGasolinCar = new GasolinCar();
teslaGasolinCar.mileage = 12;
teslaGasolinCar.type = 'Car';
teslaGasolinCar.manufacturers = "Tesla";
teslaGasolinCar.year = 2018;
console.log('Printing Tesla Car:==>');
console.log('Mileage:' + teslaGasolinCar.mileage);
console.log('Type:' + teslaGasolinCar.type);
console.log('Manufacturer:' + teslaGasolinCar.manufacturers);
console.log('Year: ' + teslaGasolinCar.year);
//Let's create Ford objects
var fordGasolinCar = new GasolinCar();
fordGasolinCar.mileage = 11;
fordGasolinCar.type = 'Car';
fordGasolinCar.manufacturers = "Ford";
fordGasolinCar.year = 2019;
console.log('Printing Ford Car:==>');
console.log('Mileage:' + fordGasolinCar.mileage);
console.log('Type:' + fordGasolinCar.type);
console.log('Manufacturer:' + fordGasolinCar.manufacturers);
console.log('Year: ' + fordGasolinCar.year);
This comment has been removed by a blog administrator.