Suppose we have this constructor:
var Foo = function(){
this.x = "y";
}
Foo and Foo.prototype.constructor evaluate to the same function, yet Foo.prototype.constructor = function(){this.x="z"} doesn’t seem to change the result of new Foo(). It does however change the result of
var i = new Foo();
i.constructor; // evals to function (){this.x = "z"}
What’s going on here? I don’t plan on using this for anything, I’m just curious about the language.
The
constructorproperty of theprototypeproperty of a function is meant to point back to the function so that you can ask an object what constructed it. It’s set up automatically as part of creating the function object (See Section 13.2 of the spec [or here for a more up-to-date version].) As you’ve seen, you can override theconstructorproperty on theFoo.prototypeif you like, to change that, but by default that’s what it’s for. For years the JavaScript specification only said that theconstructorproperty would be there and have a given default value (function Foo() { }will mean that, by default,Foo.prototype.constructorisFoo.). But starting in ES2015, that changed, and various operations in the specification now actually use theconstructorproperty, such as here, here, here, and here.(Note that the following was written before ES2015’s
classfeature was added. The below is how you’d do this in ES5 and earlier. In ES2015+, if you’re doing constructor functions and inheritance hierarchies, there’s no good reason to do the below; just useclass. [If you don’t use constructor functions to build inheritance hierarchies — and you don’t have to, there are other ways to do them in JavaScript — you wouldn’t do the below or useclass.])There’s a good reason you can override it, which relates to inheritance. Suppose you want to have a
Baseconstructor that creates base objects, and aDerivedconstructor that creates derived objects with the features ofBaseplus the additions/modifications ofDerived. The usual (though not to my mind ideal) way you see that done (absent helper scripts) is:The problem is that now,
d.constructor === Baserather thanDerived. So being able to fix that is important:(Side note: All of this plumbing — and complexity around supercalls — is why ES2015+ have
classsyntax.)Note that the above is not meant to be an ideal way to set up inheritance hierarchies. It’s what you usually see, but as I said above, not ideal. Just for completeness, in an environment limited to ES5 syntax, this is better:
…where in a pre-ES5 environment, you use a shim/polyfill for
Object.create. But again, I don’t do this directly (and don’t recommend it), I use helper scripts so it’s declarative and repeatable.