3

My question is about a strange output that I came across while playing with JS prototypal inheritance.

Please take a look:

function Parent(){
}

Parent.prototype = {
  variable : 'a'
}; 


function Child(){
}

Child.prototype = new Parent();


child = new Child();

Parent.prototype =
{
  variable : 'c'
};


console.log(child.variable);  // output a
console.log(child.__proto__);  // [object Object] { variable: 'a'}

Why the child did not inherit property?

Of course if I would do this this way:

function Parent(){
}

Parent.prototype.variable = 'a'; 


function Child(){
}

Child.prototype = new Parent();


child = new Child();

Parent.prototype.variable = 'c';

console.log(child.variable); //  "c"
console.log(child.__proto__); //  [object Object] { variable: "c"}

The output is expected: "c" and

[object Object] {
  variable: "c"
}

does anyone know why the object 'prototype' is not beeing inherited while a normal property of 'prototype' is?

JJJ
  • 32,902
  • 20
  • 89
  • 102
grzim
  • 534
  • 3
  • 10
  • 3
    Your question is more connected to how primitive and non primitive data types work. In your first example `Child.prototype` keeps the reference to the old `Parent.prototype`. In your secon example it steel keeps it and you modify its property `variable`. Totally different things. – kidwon May 31 '14 at 13:17

3 Answers3

2

Why the child did not inherit property?

difference between re assigning and mutating

re assigning:

var org = {val:22};
var copy = org;
//re assigning org de references copy
//  before this line copy === org
//  but after this line it isn't
org = {val:44};
//what do you think the value of copy is
console.log(copy.val);//=22 re assigning org de references copy

mutating:

var org = {val:22};
var copy = org;
org.val=33;//mutating org
//mutating copy (copy.val=11) would affect org
//  because org and copy are still the same (copy === org)
console.log(copy.val);//=33 because mutated org

You should not create an instance of Parent to set the prototype of Child (use Object.create instead) and in your comments you set the prototype of Child to be Parent.prototype, you can't do that because a Child is a Parent but a Parent isn't a Child (for example: a Dog is an Animal but an Animal is not a Dog because Animal could be a Snake).

More on constructor functions and prototype can be found here: https://stackoverflow.com/a/16063711/1641941

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

Child.prototype = new Parent(); will construct a new Parent-object with the current Parent.prototype object as Child.prototype.__proto__.

Using: Parent.prototype.variable = 'c'; will change the objects property variable, since it is still the same object as of Child.prototype.__proto__, the variable will be modified on Child too.

Since Parent.prototype = { variable: 'c' }; will change the Parent.prototype object, to a completely new object. But the reference of the old prototype (Child.prototype.__proto__ will still remain the old, there will be no modification.

bbuecherl
  • 1,609
  • 12
  • 20
  • I guess you mean `Child.prototype.__proto__` not `Child.prototype.prototype`. The last one is undefined. – Yury Tarabanko May 31 '14 at 13:20
  • thank you for your answer. But accordingly to that shoulnd this work when we add a line: Child.prototype.prototype = Parent.prototype; (it is not working this way as well) – grzim May 31 '14 at 13:23
  • @user3694185 : no, first see the edit on `Child.prototype.__proto__`, secondly since `Parent.prototype` is a completely new **object** `Child.prototype.__proto__` won't be updated, you still would have to reset `Child.prototype.__proto__ = Parent.prototype` or only modify the variable – bbuecherl May 31 '14 at 13:26
  • Yes! I catch it now:) As you are creating a new object for Parent.prototype the Child.__proto__ is not changed. So is there any way to recreate an object (in this case prototype) in a way that all child that are inheriting from that object will update? For example we have somewhere in a code a need to replace prototype entirely but we want to keep this change in all kids, is there any nice way to do it? Or just foreach loop and delete all hasOwnProperty and then add what we need? – grzim May 31 '14 at 13:32
  • 2
    I don't think recreating is possible without a bigger observation pattern. So i would use delete and add new. But not that you shouldn't edit prototypes to much, since it's a real hit to your page's performance – bbuecherl May 31 '14 at 13:40
1

does anyone know why the object 'prototype' is not beeing inherited …

Instances are assigned a private [[Prototype]] that is the the public prototype of their constructor when they are created. Assigning a new object to the constructor's prototype later doesn't change the [[Prototype]] of instances that have already been created, they continue to reference the original object.

So when you first construct child, it's [[Prototype]] is Child.prototype, which is an instance of Parent and therefore inherits from the Parent.prototype that existed when it was created.

When you later assign a new Parent.prototype, that doesn't change the [[Prototype]] of instances that have already been created, so Child.prototype still inherits from the original Parent.prototype, and hence child does too.

… while a normal property of 'prototype' is?

Because that just adds a new property to the existing object, it doesn't assign a new object to the prototype property of the constructor.

RobG
  • 142,382
  • 31
  • 172
  • 209