Define Inheritance
Before I dive into Inheritance in Javascript, lets first define what I understand under inheritance.
- Inheriting the implementation of an Object or Class
- Being able to override the inherited implementation
- Able to keep things private to the Object or Class
- Able to keep things private, but still accessible for inheriting Objects or Classes
- Able to access the super Object or Class
Lets see how this is done in javascript, with help of my own library EnoFJS!
(Link to EnoFJS)
Creating an Object or Class
The in my opinionĀ BAD way:
function Animal(){} | |
Animal.prototype = { | |
name: 'animal', | |
sayHello: function sayHello(){ | |
return 'Hi, my name is ' + this.name + '!'; | |
} | |
}; | |
function Dog(){} | |
Dog.prototype = new Animal(); | |
var dog = new Dog(); | |
dog instanceof Animal; //True | |
dog.sayHello(); //Hi, my name is animal! |
Why do I think this is a bad way of inheriting? Because all functions you put on the prototype, can only access public available properties and functions.
The way with EnoFJS:
var Animal = clazz(function Animal(){ | |
this.private = { | |
name: 'animal' | |
}; | |
this.public = { | |
sayHello: function sayHello(){ | |
return 'Hi, my name is ' + this.private.name + '!'; | |
} | |
}; | |
}); | |
var Dog = clazz(function Dog(){ | |
this.extend = 'Animal'; | |
}); | |
var dog = new Dog(); | |
dog instanceof Animal; //True | |
dog.sayHello(); //Hi, my name is animal! | |
dog.name; //undefined |
Overriding, but keep things private to the parent
Continuing the BAD way:
function Animal(){} | |
Animal.prototype = { | |
name: 'animal', | |
sayHello: function sayHello(){ | |
return 'Hi, my name is ' + this.name + '!'; | |
} | |
}; | |
function Dog(){} | |
Dog.prototype = new Animal(); | |
Dog.prototype.sayHello = function sayHello(){ | |
return 'Hello, my name is ' + this.name + '!'; | |
}; | |
var dog = new Dog(); | |
dog instanceof Animal; //True | |
dog.sayHello(); //Hello, my name is animal! |
Notice that the name is not private!
The way of EnoFJS:
var Animal = clazz(function Animal(){ | |
this.private = { | |
name: 'animal' | |
}; | |
this.public = { | |
sayHello: function sayHello(){ | |
return 'Hi, my name is ' + this.private.name + '!'; | |
} | |
}; | |
}); | |
var Dog = clazz(function Dog(){ | |
this.extend = 'Animal'; | |
this.public = { | |
sayHello: function sayHello(){ | |
return 'Hello, my name is ' + this.private.name + '!'; | |
} | |
}; | |
}); | |
var dog = new Dog(); | |
dog instanceof Animal; //True | |
dog.sayHello(); //Hello, my name is undefined! | |
dog.name; //undefined |
Notice that this.private.name
is only accessible for the original and therefor is resolved as undefined
for the dog
!
Protected
As displayed above, the “common practices” for inheritance in javascript, don’t really handle privacy very well. However this doesn’t mean it is impossible to achieve this, which is shown with EnoFJS. An even more tricky concept for accessibility is the protected accessibility. Through the EnoFJS library it is made possible:
var Animal = clazz(function Animal(){ | |
this.protected = { | |
name: 'animal' | |
}; | |
this.public = { | |
sayHello: function sayHello(){ | |
return 'Hi, my name is ' + this.protected.name + '!'; | |
} | |
}; | |
}); | |
var Dog = clazz(function Dog(){ | |
this.extend = 'Animal'; | |
this.public = { | |
sayHello: function sayHello(){ | |
return 'Hello, my name is ' + this.protected.name + '!'; | |
} | |
}; | |
}); | |
var dog = new Dog(); | |
dog instanceof Animal; //True | |
dog.sayHello(); //Hello, my name is animal! | |
dog.name; //undefined |
Super and Constructor!
Something even more rare in the world of javascript, is the super access. Access to the method of the parent:
var Animal = clazz(function Animal(){ | |
this.private = { | |
name: 'animal' | |
}; | |
this.public = { | |
sayHello: function sayHello(){ | |
return 'Hi, my name is ' + this.private.name + '!'; | |
} | |
}; | |
this.constructor = function constructor(name){ | |
this.private.name = name; | |
}; | |
}); | |
var Dog = clazz(function Dog(){ | |
this.extend = 'Animal'; | |
this.public = { | |
sayHello: function sayHello(){ | |
return this.super.sayHello() + ' How are you?'; | |
} | |
}; | |
this.constructor = function constructor(name){ | |
this.super.constructor(name); | |
}; | |
}); | |
var dog = new Dog('Brian'); | |
dog instanceof Animal; //True | |
dog.sayHello(); //Hello, my name is Brian! How are you? | |
dog.name; //undefined |
After match
- Inheriting the implementation of an Object or Class
Easy achievable without a library - Being able to override the inherited implementation
Achievable without library, but no private scoping
With EnoFJS, it is achievable even with private scoping! - Able to keep things private to the Object or Class
So far I’ve only seen it made possible with BackboneJS and EnoFJS - Able to keep things private, but still accessible for inheriting Objects or Classes
Something I have only seen with EnoFJS - Able to access the super Object or Class
Something I have only seen with EnoFJS
Conclusion
Javascript is so dynamic, it opens so many possibilities! With the help of a little library(less then 2kb), we are able to do full inheritance with private
, protected
and even super
access!