Trying to bend by head around Javascript\'s take on OO...and, like many others, running into confusion about the constructor
property. In particular, the signif
September 2020 Update
The answer below is from the days of ECMAScript 3 and the first sentence is no longer true because since ECMAScript 6, the constructor
property is used in a few places. However, I think the overall gist still applies. Thanks to T. J. Crowder for pointing that out in the comments, and please read his answer for a fuller picture of the current situation.
Original answer
The constructor
property makes absolutely no practical difference to anything internally. It's only any use if your code explicitly uses it. For example, you may decide you need each of your objects to have a reference to the actual constructor function that created it; if so, you'll need to set the constructor
property explicitly when you set up inheritance by assigning an object to a constructor function's prototype
property, as in your example.
One of the use cases when you would want the prototype.constructor
property to survive prototype
property reassignment is when you define a method on the prototype
that produces new instances of the same type as the given instance. Example:
function Car() { }
Car.prototype.orderOneLikeThis = function() { // Clone producing function
return new this.constructor();
}
Car.prototype.advertise = function () {
console.log("I am a generic car.");
}
function BMW() { }
BMW.prototype = Object.create(Car.prototype);
BMW.prototype.constructor = BMW; // Resetting the constructor property
BMW.prototype.advertise = function () {
console.log("I am BMW with lots of uber features.");
}
var x5 = new BMW();
var myNewToy = x5.orderOneLikeThis();
myNewToy.advertise(); // => "I am BMW ..." if `BMW.prototype.constructor = BMW;` is not
// commented; "I am a generic car." otherwise.
Step one is to understand what constructor
and prototype
are all about. It's not difficult, but one has to let go of "inheritance" in the classical sense.
The constructor
The constructor
property does not cause any particular effects in your program, except that you can look at it to see which function was used in conjunction with the operator new
to create your object. If you typed new Bar()
it will be Bar
and you typed new Foo
it will be Foo
.
The prototype
The prototype
property is used for lookup in case the object in question does not have the property asked for. If you write x.attr
, JavaScript will try to find attr
among x
's attributes. If it cant find it, it will look in x.__proto__
. If it's not there either, it will look in x.__proto__.__proto__
and so on as long as __proto__
is defined.
So what is __proto__
and what has it got to do with prototype
? Shortly put, prototype
is for "types" while __proto__
is for "instances". (I say that with quotation marks because there's not really any difference between types and instances). When you write x = new MyType()
, what happens (among other things) is that x.__proto___
is set to MyType.prototype
.
The question
Now, the above should be all you need to derive what your own example means, but to try and answer your actual question; "why write something like":
Bar.prototype.constructor = Bar;
I personally have never seen it and I find it a little silly, but in the context you've given it will mean that the Bar.prototype
-object (created by using new Foo(42)
) will pose as have being created by Bar
rather than Foo
. I suppose the idea is some make something similar to C++/Java/C#-like languages where a type-lookup (the constructor
property) will always yield the most specific type rather than the type of the more generic object further up in the prototype-chain.
My advice: don't think very much about "inheritance" in JavaScript. The concepts of interfaces and mixins makes more sense. And don't check objects for their types. Check for the required properties instead ("if it walks like a duck and quacks like a duck, it's a duck").
Trying to force JavaScript into a classical inheritance model, when all that it has is the prototype-mechanism as described above, is what causes the confusion. The many people that suggested to manually set the constructor
-property probably tried to do just that. Abstractions are fine, but this manual assignment of the constructor property is not very idiomatic usage of JavaScript.
one case to use constructor:
this is one of the common realization of inheritance:
Function.prototype.extend = function(superClass,override) {
var f = new Function();
f.prototype = superClass.prototype;
var p = this.prototype = new f();
p.constructor = this;
this.superclass = superClass.prototype;
...
};
this new f()
would not call the constructor of superClass,so when you create a subClass,maybe you need call the superClass at first,like this:
SubClass = function() {
SubClass.superClass.constructor.call(this);
};
so the constructor property make sense here.
The previous answers here say (in various ways) that the value of the constructor
property isn't used by anything in JavaScript itself. That was true when those answers were written, but ES2015 and onward have started using constructor
for things.
The constructor
property of the prototype
property 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 a traditional function object or a class constructor object (details).
function TraditionalFunction() {
}
console.log(TraditionalFunction.prototype.constructor === TraditionalFunction); // true
class ExampleClass {
}
console.log(ExampleClass.prototype.constructor === ExampleClass); // true
Arrow functions don't have a prototype
property, so they don't have prototype.constructor
.
For years the JavaScript specification only said that the constructor
property would be there and have that value (a link back to the function) by default. But starting in ES2015, that changed, and various operations in the specification now actually use the constructor
property, such as this, this, this, and this.
So when setting up constructor functions that build inheritance chains, it's best to ensure that the constructor
property is referring to the appropriate function. See my answer here for examples, etc.
The constructor property points to the constructor that was used to create the object instance. If you typed 'new Bar()' it will be 'Bar' and you typed 'new Foo()' it will be 'Foo'.
But if you set the prototype without setting the constructor, you would get something like this:
function Foo(age) {
this.age = age;
}
function Bar() {
this.name = "baz";
}
Bar.prototype = new Foo(42);
var one = new Bar();
console.log(one.constructor); // 'Foo'
var two = new Foo();
console.log(two.constructor); // 'Foo'
To set the constructor actually to the constructor that was used to create the object, we need to set the constructor as well while setting prototype as follows:
function Foo(age) {
this.age = age;
}
function Bar() {
this.name = "baz";
}
Bar.prototype = new Foo(42);
Bar.prototype.constructor = Bar;
var one = new Bar();
console.log(one.constructor); // 'Bar'
var two = new Foo();
console.log(two.constructor); // 'Foo'