We know that modern object-oriented programming languages provide inheritance to make life easier.
The lives of software developers that helplessly stray through jungles of inheritance hierarchies nobody found worth to document?
The lives of managers that can be sure that the maintenance of the software they sell will not make up 80% of the manufacturing costs, because it was written using OO techniques?
Inheritance lets us re-use existing, working and tested solutions, without any adapter code.
When using inheritance, we want to ...
So I want inheritance also in JavaScript. And I am confused about the many kinds of inheritance that seem to be available in JS, the most popular being
The following is a kind of inheritance I developed during my JS studies. It is a slight extension of what is called "functional inheritance". It ...
this
" nor "new
" keywordsMind that it does not support the instanceof
operator, I consider that being an anti-pattern.
Base of this kind of inheritance are functions that create objects.
Here are basic factory functions for an "animal" inheritance tree:
1 | var animal = function(species) { |
Every hierarchy level is represented by exactly one function that creates an object representing that inheritance level.
The base function animal()
first creates a new empty object, because this is the base of the inheritance hierarchy. It populates that object with some general properties and functions all animals should have.
Mind that there is a call to a function called sound()
that does NOT exist in the object returned from animal()
. I would call this an "abstract function", to be implemented by sub-objects of animal.
The function mammal()
then "extends" animal()
by calling it, copying the returned animal, and then enriching it with properties and functions of a mammal.
Copying is optional, only needed if a mammal wants to use overwritten super-functions or -properties. Each inheritance level would see only its direct ancestor, but as all properties/functions of the super-object are copied into the more specialized object, the final sub-object would see all properties/functions of all levels, except the overwritten ones.
A mammal also uses an "abstract function" create()
, and it overwrites toString()
and calls super.toString()
, which is named superToString
here (super
is a JS reserved word).
Here comes the usual cat and dog stuff.
1 | var cat = function(name) { |
These two sub-objects both must implement the "abstract functions", which is sound()
and create()
in this case.
Mind that I can reference the function dog()
within its own function body for the create()
function!
For both factories I could have dropped the shallowCopy()
call, because neither needs a super-call.
Also a create()
function is necessary only when a Cat instance must be able to create another Cat instance.
Here is some test code ...
1 | var garfield = cat("Garfield"); |
Garfield: I am 'Garfield', species 'Cat', belly(catfish), sounding Meaou
Garfield's baby: I am 'LittleGary', species 'Cat', belly(empty), sounding Meaou
Pluto: I am 'Pluto', species 'Dog', belly(t-bone), sounding Wouff Wouff
Pluto's baby: I am 'LittleBloody', species 'Dog', belly(empty), sounding Wouff Wouff
Stepped into no gotcha, there are no bellies shared amongst these animals :-)
But, as I said before, the following prints false:
console.log("garfield instanceof cat: "+(garfield instanceof cat)); |
Reason is that there is no prototype
used, and no new
operator.
Here are some arguments against code using instanceof
, which ...
Surprise: in functional inheritance private variables seem to work!
Try following example:
1 | var vehicle = function(type) { |
The factory function motorbike()
hosts a local variable storing the number of wheels of the vehicle. It has an initial value, and a public function can increment that value. And as we see, each motorbike instance has its own wheel counter!
Following test code
1 | var myMotorbike = motorbike("My"); |
outputs this:
My motorbike has 2 wheels
Your motorbike has 2 wheels
Increasing wheels on My motorbike to 3
My motorbike has 3 wheels
Your motorbike has 2 wheels
His motorbike has 2 wheels
Increasing wheels on Your motorbike to 3
Increasing wheels on Your motorbike to 4
My motorbike has 3 wheels
Your motorbike has 4 wheels
His motorbike has 2 wheels
To achieve module-encapsulation together with inheritance, JS functional inheritance provides all needed features.
ɔ⃝ Fritz Ritzberger, 2014-10-19