Reputation: 3928
While this below implementation seems good, because it allows a child to have its own copy of own members (without having ability to modify parent's own members), plus it uses the prototype chain, so properties won't be recreated for each object instantiation, it is not efficient because the Parent constructor is invoked twice (once for apply and new Parent instantiation):
function Parent(a,b,c,d){
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
Parent.prototype.say_a = function(){
return this.a;
}
Parent.prototype.say_b = function(){
return this.b;
}
Parent.prototype.say_c = function(){
return this.c;
}
Parent.prototype.say_d = function(){
return this.d;
}
Parent.prototype.not_going_to_be_copied = function(){
console.log(“This function will not be recreated from one object instantiation to the next, making it very efficient.”);
}
function Child(a,b,c,d){
Parent.apply(this,arguments);
}
Child.prototype = new Parent();
c = new Child("a","b","c","d");
console.log([c.say_a(),c.say_b(),c.say_c(),c.say_d()].join(" "));
Stoyan in Javascript Patterns mentions this alternative, which does not invoke Parent constructor at all:
Child.prototype = Parent.prototype;
However, he says a drawback to this is if one child or grandchild somewhere down the inheritance chain modifies the prototype, it affects all parents and grandparents.
However, I cannot reproduce that claim:
function Parent(){}
Parent.prototype.set_a = function(a){
this.a = a;
}
Parent.prototype.get_a = function(){
return this.a;
}
function Child(){}
Child.prototype = Parent.prototype;
var c = new Child();
var p = new Parent();
c.set_a("a");
console.log(c.get_a()); // a
p.set_a("b");
console.log(p.get_a()); // b
console.log(c.get_a()); // a
c.prototype = {};
console.log("after mod " + c.get_a()); // after mod a
console.log("after mod " + p.get_a()); // after mod b
c.get_a = function(){return "am I changing parent?"}
console.log(c.get_a()); // am I changing parent?
console.log(p.get_a()); // b
As you can see, no matter how I modify the prototype of Child, it does not affect the prototype of Parent. So am I missing something? Can the children's modification of prototype have affect on the Parent?
Upvotes: 1
Views: 1037
Reputation: 39270
Child.prototype = Parent.prototype;
Is bad because if Child is a Dog and Parent is Animal we can say a Dog is an Animal but we can't say an Animal is a Dog (what about a Snake?).
Here is where it goes wrong
var Animal=function(){};
var Snake = function(){};
Snake.prototype=Animal.prototype;
var Dog = function(){};
Dog.prototype=Animal.prototype;
Dog.prototype.bark=function(){console.log('I am barking');};
var aSnake = new Snake();
aSnake.bark();//I am barking ???
It's better to use Object.crate to set prototype of Child instead of setting it to an instance of Parent because Parent has instance specific members that should not be on Child and you may have a situation where Parent constructor needs parameters passed that are not available when declaring the Child type (and it's just bad form).
In your code c.get_a
is shadowing the prototype member and does not affect the prototype. This is explained in detail here.
Upvotes: 1
Reputation: 61885
After Child.prototype = Parent.prototype
the same object is bound to both constructors' prototype property (and is fairly silly, IMOHO). Thus modifying the object known as Child.prototype
also modifies Parent.prototype
which "affects all" as claimed because both expressions evaluate to the same object.
Consider if later on;
Child.prototype.hello = "Hello world"
// Noting that
Child.prototype === Parent.prototype // -> true, as per initial condition
Then;
var p = new Parent()
p.hello // -> "Hello world", showing the "affecting" behavior
So it can be see that modifying Child.prototype affected the [prototype] of instances of Parent as well - because the same object was modified.
However, the issue isn't being reproduced because one cannot "assign the prototype of an instance" in such a manner. That is, the [prototype] chain is only set based of the constructor's prototype property (or via Object.create), at time of creating a new instance. Assigning to the prototype property of an instance is .. just assigning a normal property.
var c = new Child()
c.prototype = "Hello world"
typeof c.say_a // -> "function", didn't assign [prototype]
c.prototype // -> "Hello world"
c.__proto__ === Child.prototype // -> true, in browsers supporting __proto__
Upvotes: 1