Mayank
Mayank

Reputation: 259

Constructor property of an object

I came across this example while reading the prototype.

function Animal(){
    this.name = 'Animal'
}

var animal1 = new Animal();

function Rabbit(){
    this.canEat = true;
}

Rabbit.prototype = new Animal();

var r = new Rabbit();

console.log(r.constructor)

And the console is giving me Animal as the output for r.constructor, which is a little confusing as the constructor property should have returned Rabbit as r is created by invoking Rabbit with the new operator.

Also, if I invoke the Rabbit function before assigning the prototype it gives me the desired result.

Upvotes: 1

Views: 112

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1075915

Objects inherit constructor from their prototype (typically); they get their prototype from the prototype property of the constructor function that creates them when they're created (if they're created by a constructor function). Rabbit.prototype's constructor is incorrect, because of this:

Rabbit.prototype = new Animal();

That calls Animal to create a new instance, and assigns that instance as Rabbit.prototype. So its constructor, inherited from Animal.prototype, is Animal. You've replaced the default object that used to be on Rabbit.prototype (which had constructor set to Rabbit).

In general, that Rabbit.prototype = new Animal() is not the best way to set up inheritance. Instead, you do it like this:

Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;

and then in Rabbit:

function Rabbit() {
    Animal.call(this);    // ***
    this.name = "Rabbit"; // Presumably we want to change Animal's deafult
    this.canEat = true;
}

Three changes there:

  1. We don't call Animal when setting up the inheritance, we just create a new object that uses Animal.prototype as its prototype, and put that on Rabbit.prototype.
  2. We set constructor on the new object we've assigned to Rabbit.prototype.
  3. We do call Animal when initializing the instance (in Rabbit).

Live Example:

function Animal(){
    this.name = 'Animal'
}

var animal1 = new Animal();

function Rabbit() {
    Animal.call(this);    // ***
    this.name = "Rabbit"; // Presumably we want to change Animal's deafult
    this.canEat = true;
}

Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;


var r = new Rabbit();
console.log(r.constructor);


Or, of course, use ES2015+ class syntax, which handles this plumbing for you (along with a few other benefits).

class Animal {
    constructor() {
        this.name = "Animal";
    }
}

class Rabbit extends Animal {
    constructor() {
        super();
        this.name = "Rabbit";
        this.canEat = true;
    }
}

const r = new Rabbit();
console.log(r.constructor);

Upvotes: 5

Related Questions