Understanding ES5 Classes, Constructors, Prototypes, and Prototype Chains in JavaScript
Before ES6 specifications were established, classes in JavaScript were essentially constructor functions. This article explores the relationship between constructors, prototypes, and prototype chains in ES5.
- A Simple Constructor Function
this.id = id;
this.salary = salary;
}
var emp = new Employee(1001, 5000);
console.log(emp.id);
- Static Methods in ES5
function Employee(){}
Employee.calculateBonus = function(baseSalary, performanceRating){
return baseSalary * performanceRating * 0.1;
}
console.log(Employee.calculateBonus(5000, 1.5));
- Inheritance Through Object Impersonation (Constructor Stealing)
function Person(name, title){
this.name = name;
this.title = title;
this.introduce = function(){
console.log(this.name + ' - ' + this.title);
}
}
Person.prototype.company = 'TechCorp';
Person.prototype.getCompany = function(){
console.log(this.name + ' works at ' + this.company);
}
function Manager(name, title){
Person.call(this, name, title);
}
var mgr = new Manager('Alice', 'Engineering Manager');
mgr.introduce();
mgr.getCompany();
- Inheritance Through Prototype Chain
function Person(name, title){
this.name = name;
this.title = title;
this.introduce = function(){
console.log(this.name + ' - ' + this.title);
}
}
Person.prototype.company = 'TechCorp';
Person.prototype.getCompany = function(){
console.log(this.name + ' works at ' + this.company);
}
function Manager(name, title){}
Manager.prototype = new Person();
var mgr = new Manager('Alice', 'Engineering Manager');
mgr.introduce();
mgr.getCompany();
- Problem with Pure Prototype Chain Inheritance
function Person(name, role){
this.name = name;
this.role = role;
this.describe = function(){
console.log(this.name + ' is a ' + this.role);
}
}
function Developer(name, role){}
Developer.prototype = new Person();
var dev = new Developer('Bob', 'Frontend Dev');
dev.describe();
In the example above, when instantiating the subclass, the parent constructor cannot receive parameters, causing potential issues.7. Combined Approach: Prototype Chain + Constructor Stealing
function Person(name, role){
this.name = name;
this.role = role;
this.describe = function(){
console.log(this.name + ' is a ' + this.role);
}
}
function Developer(name, role){
Person.call(this, name, role);
}
Developer.prototype = new Person();
var dev = new Developer('Bob', 'Frontend Dev');
dev.describe();
- Alternative Combined Inheritance Pattern
function Person(name, role){
this.name = name;
this.role = role;
this.describe = function(){
console.log(this.name + ' is a ' + this.role);
}
}
function Developer(name, role){
Person.call(this, name, role);
}
Developer.prototype = Person.prototype;
var dev = new Developer('Charlie', 'Backend Dev');
dev.describe();
Relationship Between Functions, Object, Prototypes, and Prototype Chains
Understanding the constructor property is essential. Consider the following example:
function Developer(name, programmingLanguage, experienceYears){
this.name = name;
this.programmingLanguage = programmingLanguage;
this.experienceYears = experienceYears;
}
var dev = new Developer('Eve', 'JavaScript', 5);
console.log(dev.constructor);
console.log(dev.__proto__);
console.log(Developer.prototype);
console.log(Developer.__proto__ === Function.prototype);
Key observations:
1): In JavaScript, new can be used in three scenarios: new + constructor function, new + Function(), and new + Object().
***The constructor property of an object points too its constructor function.******The constructor of Function.prototype is Function.***The constructor of Object.prototype is Object.
2): The proto property of an object is used to access its constructor's prototype. Every object has this property.
3): The instanceof operator checks for constructor relationships.
4): The constructor property on a function's prototype equals the function itself: Constructor.prototype.constructor === Constructor