1

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?

JohnMerlino
  • 3,900
  • 4
  • 57
  • 89
  • This seems like a good question. It also just seems like you to write more JavaScript code, and experiment with Objects. What is the question here? – Ryan Aug 31 '14 at 01:42
  • You might want to look at what you're setting the `.prototype` property on in your last example. – Qantas 94 Heavy Aug 31 '14 at 01:44
  • Stoyan says "if one child or grandchild somewhere down the inheritance chain modifies the prototype, it affects all parents and grandparents", however, I cannot reproduce that. I modified the protoype of child in different ways and still the parent has the same prototype values it had. It appears child modification of prototype has no affect on parent, contrarty to what he says. – JohnMerlino Aug 31 '14 at 01:45
  • @Qantas94Heavy can you elaborate? – JohnMerlino Aug 31 '14 at 01:47
  • 3
    @JohnMerlino: it appears you're mistaking what the `.prototype` property does on constructor functions vs what they do on instances (i.e. nothing). – Qantas 94 Heavy Aug 31 '14 at 01:50
  • [`Child.prototype = Parent.prototype;` is just blatantly wrong](http://stackoverflow.com/q/11088365/1048572) – Bergi Aug 31 '14 at 12:16

2 Answers2

1

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__
user2864740
  • 60,010
  • 15
  • 145
  • 220
  • That comment confuses me. A string cannot be assigned to the [value of the] constructor. A constructor is just a function, and an identifier is just an identifier - which can evaluate to a value if it is appropriately bound. – user2864740 Aug 31 '14 at 02:07
  • Let me explain it easier. The word "affect" to me means that if I reassign a value to Child, it should change the value of Parent. So look at this: Child.prototype = {}; console.log(Parent.prototype.get_a); After I assigned a blank Object to Child, Parent still thinks it has a get_a function. In other words, Parent.prototype.get_a does NOT produce undefined! – JohnMerlino Aug 31 '14 at 02:12
  • 2
    @JohnMerlino Assigning a *different object* to Child.prototype *does not modify* Parent or the object bound to Parent.prototype. Thus the behavior make sense. The "affecting all" is when the *same object* is mutated, as shown. (This behavior is the same as for other JavaScript properties/objects and has nothing to do with prototypes.) – user2864740 Aug 31 '14 at 02:13
  • I see it now, for some reason, the firefox firebug console was cached for me. When I restarted firefox and tried again, the changes took affect. – JohnMerlino Aug 31 '14 at 02:21
  • @JohnMerlino Cool, glad it's sorted out. – user2864740 Aug 31 '14 at 02:22
1
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.

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160