4

I find the behaviour of this piece of code puzzling, why is the constructor of child not Child? Can someone please explain this to me?

function Parent() {
    this.prop1 = "value1";
    this.prop2 = "value2";
}

function Child() {
    this.prop1 = "value1b";
    this.prop3 = "value3";
}
Child.prototype = new Parent();

var child = new Child();

// this is expected
console.log(child instanceof Child); //true
console.log(child instanceof Parent); //true

// what??
console.log(child.constructor == Child); //false
console.log(child.constructor == Parent); //true
einarmagnus
  • 3,507
  • 1
  • 21
  • 31
  • This question appears to be a dup of [this one](http://stackoverflow.com/questions/2479349/constructors-and-inheritance-in-js) - but I find this question's answers more useful. +1s all around :) – Matt Ball Oct 29 '10 at 02:22

2 Answers2

5

As Pointy has pointed out, in his answer

The "constructor" property is a reference to the function that created the object's prototype, not the object itself.

The usual way to deal with this is to augment the object's prototype constructor property after assigning to the prototype

function Parent() {
    this.prop1 = "value1";
    this.prop2 = "value2";
}

function Child() {
    this.prop1 = "value1b";
    this.prop3 = "value3";
}
Child.prototype = new Parent();

// set the constructor to point to Child function
Child.prototype.constructor = Child;

var child = new Child();

// this is expected
console.log(child instanceof Child); //true
console.log(child instanceof Parent); //true

// corrected
console.log(child.constructor == Child); // now true
console.log(child.constructor == Parent); // now false

console.log(Child.prototype.constructor); // Child
console.log(Parent.prototype.constructor); // Parent

I can't recommend Stoyan Stefanov's Object Oriented JavaScript enough which covers Prototype and Inheritance in some detail (get the second edition if you can as it addresses some critiques of the first edition).

Community
  • 1
  • 1
Russ Cam
  • 124,184
  • 33
  • 204
  • 266
  • thank you for the tip, maybe I'll order it, although the 2nd edition does not seem to be ready yet. – einarmagnus Oct 10 '10 at 22:41
  • 1
    this solution means that if I were to create a sibling of Child, i.e another `function Sibling(){}; Sibling.prototype = /* expression */; var sibling = new Sibling()`, then `expression` would have to be `new Parent()` and not the same parent object as Child, i.e `Child.prototype != Sibling.prototype`. Is this how it is usually done? I like the philosophy of prototypal inheritence but this seems like a very convoluted way of doing it. – einarmagnus Oct 10 '10 at 22:52
  • Yes, you wouldn't be able to assign the same instance of `Parent` to the `prototype` of both `Child` and `Sibling` as any changes to the `prototype` of either Child or Sibling will affect the other. For example, setting the `constructor` of one will change it for both. – Russ Cam Oct 29 '10 at 19:56
4

The "constructor" property is a reference to the function that created the object's prototype, not the object itself.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • which in this case comes from the object returned by the `Parent` constructor function and assigned to the `Child.prototype` – Russ Cam Oct 10 '10 at 19:26
  • Right, exactly. I've been trying to find a site/blog I read a few months ago that had a good explanation (with good diagrams), and if I do I'll link it. – Pointy Oct 10 '10 at 19:29
  • no, the object itself is `child`, but it was constructed by `Child` (note the capital letter). It seems like a(nother) design flaw of JS that this would point to the object's prototype's constructor and not the object's constructor. – einarmagnus Oct 10 '10 at 20:47