Some programmers advise against using pseudo classical inheritance in Javascript, but advise using duck-typing and giving each object a set of capabilities.
Is there
Functions in JavaScript are versatile. They can be used as subroutines, methods, constructors, namespaces, modules, and much more.
The reason people advise against using pseudo classical inheritance in JavaScript is because it hides the true power of JavaScript. Functions are just as expressive if not more expressive than objects. This has been proven by Alonzo Church who's work, Lambda Calculus, is Turing Complete.
To answer your question directly I'll use functions to create a Turtle
, a Lion
and a Dolphin
. Then I'll demonstrate how a turtle is an OceanAnimal
and a LandAnimal
, how a lion is only a LandAnimal
, and how a dolphin is only an OceanAnimal
. I'll conclude by explaining what is duck typing.
First let's create the constructor for an OceanAnimal
:
function OceanAnimal() {
this.swim = function (n) {
return "I am " + this.name + ", the " + this.type +
", and I just swam " + n + " meters.";
};
}
Next we'll create the constructor for a LandAnimal
:
function LandAnimal() {
this.walk = function (n) {
return "I am " + this.name + ", the " + this.type +
", and I just walked " + n + " meters.";
};
}
Alright. So now let's create the constructor for a Turtle
:
Turtle.prototype.type = "turtle";
function Turtle(name) {
this.name = name;
LandAnimal.call(this);
OceanAnimal.call(this);
}
What's happening here? Okay, we want Turtle
to inherit from both OceanAnimal
and LandAnimal
. So we're calling LandAnimal.call(this)
and OceanAnimal.call(this)
. In this way we're using the OceanAnimal
and LandAnimal
constructors as mixins. Thus Turtle
inherits from both OceanAnimal
and LandAnimal
without actually becoming of type OceanAnimal
or LandAnimal
.
Another thing to notice is that we're setting the type
property on the prototype
of Turtle
instead of inside it. This is because type
is the same for all turtles. Thus it's shared. The name
of each turtle on the other hand may vary and hence it's set inside the constructor.
Now let's similarly create the constructor for a Lion
:
Lion.prototype.type = "lion";
function Lion(name) {
this.name = name;
LandAnimal.call(this);
}
Since Lion
is a LandAnimal
we only mix in the LandAnimal
constructor.
Similarly for a Dolphin
:
Dolphin.prototype.type = "dolphin";
function Dolphin(name) {
this.name = name;
OceanAnimal.call(this);
}
Now that we have created all the constructors let's create a turtle, a lion and a dolphin:
var yoyo = new Turtle("Yoyo");
var simba = new Lion("Simba");
var dolphy = new Dolphin("Dolphy");
Awww, now let's set them free:
alert(yoyo.walk(10));
alert(yoyo.swim(30)); // turtles are faster in the water
alert(simba.walk(20));
alert(dolphy.swim(20));
Haha. That was fun. Personally I love yoyo the most.
Okay, so what's duck typing? We know that yoyo is an OceanAnimal
and a LandAnimal
. However if we do yoyo instanceof OceanAnimal
or yoyo instanceof LandAnimal
then it returns false
. What?
Turtle
is an OceanAnimal
and a LandAnimal
!Turtle
.OceanAnimal
, and if it walks then it's a LandAnimal
.So since JavaScript is such a party pooper we'll have to create our own test to check if an object is an OceanAnimal
and if it's a LandAnimal
.
Let's start with an OceanAnimal
:
function isOceanAnimal(object) {
if (typeof object !== "object") return false;
if (typeof object.swim !== "function") return false;
return true;
}
Similarly, for a LandAnimal
:
function isLandAnimal(object) {
if (typeof object !== "object") return false;
if (typeof object.walk !== "function") return false;
return true;
}
So now we can use isOceanAnimal(yoyo)
instead of yoyo instanceof OceanAnimal
, and isLandAnimal(yoyo)
instead of yoyo instanceof LandAnimal
; and both these functions will return true
for our beloved yoyo. Yay!
This is a simple example of duck typing in JavaScript. To conclude:
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.
Similarly:
When I see an animal which swims like an ocean animal, I call that animal an ocean animal; and when I see an animal which walks like a land animal, I call that animal a land animal.
Edit: You can see the above code in action here: http://jsfiddle.net/aaditmshah/X9M4G/