Carlos Carlos - 16 days ago 5
Javascript Question

practical use prototype.constructor in javascript

In Simple words why we use

prototype.constructor
. I am reading an article about inheritance where I saw
prototype.constructor
. I see no difference in result when I comment that code. So my question why and when to use it practically.

function Mammal(name){
this.name=name;
this.action= function (){
alert('0')
}

}



function Cat(name){
this.name=name;
}

Cat.prototype = new Mammal();

//Cat.prototype.constructor=Cat; // Otherwise instances of Cat would have a constructor of Mammal



Cat.prototype.action=function(){
alert('1')
}

var y= new Mammal()
var x= new Cat()

y.action()

x.action()

Answer

It's mostly convention. Although nothing in JavaScript itself uses the constructor property, sometimes people use it in their code, assuming that it will refer back to the object's constructor. It's not just convention anymore, see ¹ for details.

When you create a function:

function Cat() {
}

The function starts out with an object on its prototype property that has a property called constructor that points back to the function:

console.log(Cat.prototype.constructor === Cat); // true

This is in the specification. (It's also the only place in the specification that property is mentioned — e.g., JavaScript, itself, makes no use of this property at all. Not anymore.¹)

Consequently, instances created with that prototype (whether created via the constructor function or other ways) inherit that constructor property:

var c = new Cat();
console.log(c.constructor === Cat);  // true

var c2 = Object.create(Cat.prototype);
console.log(c2.constructor === Cat); // true, even though Cat wasn't used

When you replace the prototype property on a function, as you typically do when building hierarchies:

Cat.prototype = new Mammal(); // This is an anti-pattern, btw, see below

...you end up with an object on Cat.prototype where constructor points to Mammal. Since that's not what one normally expects, it's customary to fix it:

Cat.prototype.constructor = Cat;

Although nothing in JavaScript itself uses the property (it does now¹), sometimes people use it in their code, assuming that it will refer back to the object's constructor.


Re the anti-pattern in that code: When using constructor functions to build a hierarchy, it's not best practice to actually call the "base" constructor to create the "derived" constructor's prototype. Instead, use Object.create to create the prototype:

Cat.prototype = Object.create(Mammal.prototype);
Cat.prototype.constructor = Cat;

...and then chain to Mammal in Cat:

function Cat() {
    Mammal.call(this);
    // ...
}

Why do it that way? Consider: What if the base requires arguments you won't get until construction-time to meaningfully initialize an instance? You can't pass it arguments until you have them. The pattern above allows you to handle that situation.

Note that Object.create was added in ES5 and so is missing from some old browsers (like IE8). The single-argument version of it can be shimmed/polyfilled trivially, though:

if (!Object.create) {
    Object.create = function(proto, props) {
        if (typeof props !== "undefined") {
            throw new Error("The second argument of Object.create cannot be shimmed.");
        }
        function f() { }
        f.prototype = proto;
        return new f;
    };
}

I'll just note that constructor functions are just one way of building object hierarchies in JavaScript. They're not the only way, because JavaScript uses prototypical inheritance. JavaScript is so powerful you can use constructor functions to get something similar to class-like inheritance, but it also lets you do more traditional prototypical-style inheritance directly.


¹ "Although nothing in JavaScript itself uses the constructor property..." That's not true anymore as of ES2015 (aka "ES6"). Now, the constructor property is used in a couple of places (such as the SpeciesConstructor and ArraySpeciesCreate abstract operations), which are used in various classes that have methods returning new instances of the class, such as Array#slice and Promise#then. It's used in those places to ensure that subclasses work correctly: E.g., if you subclass Array, and use slice on an instance of the subclass, the array returned by slice is an instance of your subclass, not a raw Array — because slice uses ArraySpeciesCreate.