I have read through some tutorials about javascript prototypal inheritance patterns but I am not sure which is the best practice out of the following two. I noted that many people do this inheritance pattern:
var A = function (){}
A.prototype = {}
var B = function () {
A.apply(this, arguments); // Calling the constructor of A
}
B.prototype = new A(); // Inherit from A through an instance
Alternative, there are some sources that do the following pattern instead:
var A = function (){}
A.prototype = {}
var B = function () {
A.apply(this, arguments); // Calling the constructor of A
}
for (var prop in A.prototype) {
B.prototype[prop] = A.prototype[prop]; // Inherit from A by copying every property/methods from A
}
Although both patterns work, I rarely see people use the latter inheritance pattern (ie. copying each property/methods from the parent's prototype) - why? Is there something wrong with copying properties/methods directly from parent to child? Also, are these two patterns intrinsically different in some ways?
Thank you.
These patterns are very different, and as you may have guessed, the first is better (but not the best possible). Let us compare:
B.prototype = Object.create(A.prototype);
This uses the Object.create
function to set B.prototype
to a new object, whose internal [[Prototype]]
is A.prototype
. This is basically exactly what you want: it will make B
instances delegate to A.prototype
when appropriate.
B.prototype = new A();
This was how things used to be done, before ES5's Object.create
came about. (Although there were workarounds, even if they were not widely used.) The problem with this approach is that any instance-only data properties also end up on B.prototype
, which is not desired. Additionally, any side effects of calling A
's constructor will happen. Essentially this approach muddles two related, but different concepts: object instantiation, and object construction.
for (var prop in A.prototype) {
B.prototype[prop] = A.prototype[prop];
}
This pattern has several problems:
A
's prototype chain, all the way down to Object
, directly into B.prototype
. This defeats much of the purpose of prototypal inheritance, wherein you should be delegating up the prototype chain, instead of squashing it into one single level.A.prototype
and its prototype chain, since for ... in
skips non-enumerable properties.A.prototype
(or its prototype chain), simply copying over their value instead of the getter/setter functions.Here is another method using the factory pattern, no prototypes:
/* parent */
function Animal(name, legs)
{
/* members and methods declared within a new object */
var obj =
{
name: name,
legs: legs,
description: function ()
{
return this.name + " is an animal";
},
printNumLegs: function ()
{
return this.name + " has " + this.legs + " legs";
}
}
return obj;
}
/* subclass */
function Cat()
{
/* apply parent arguments in the context of the current object */
var obj = Animal.apply(this, arguments);
/* public member */
obj.furColor = "black";
/* private member */
var sleeping = false;
/* private method */
function printSleepingState()
{
/* can access public member ('name') without it being passed as constructor argument */
return obj.name + " is " + (sleeping ? "sleeping" : "not sleeping");
}
/* declare a new method */
obj.printFurColor = function ()
{
return obj.name + " has " + obj.furColor + " fur";
}
/* overloading */
/* save parent method if needed */
var oldDescription = obj.description;
obj.description = function ()
{
return oldDescription.apply(obj) + " and " + printSleepingState();
}
return obj;
}
/* create object without new */
var kitty = Cat("Kitty", 4);
kitty.furColor = "yellow";
There is no "best" method anyway...it's all a matter of taste.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With