When i think about the constructor, i think about the function called when a class is instantiated. Well, that is true about Java but i would like to write about the constructor in Javascript.
For me is a challenge write about the constructor; after years of Javascript i still see it as something confusing; anyway recently i had the opportunity to go through it and i would like to write here some considerations.
Well, as introduction i think is good to give some definitions, distinguishing between two kinds of constructor:
- constructor functions: functions designed to be instantiated.
- constructor property: a property of the prototype pointing back to the constructor function
(keep in mind that every function in js, when defined, gets its own prototype object).
Well, quite confusing introduction, here an example of what i am saying:
var MyType = function(){}; MyType.prototype.constructor === MyType; // true var test = new MyType(); test.constructor === MyType; // true : got from prototype test instanceof MyType; // true
Sometimes i have seen “classes” (i should say objects) defined in this way:
var MyType = function(){}; MyType.prototype = { method1: function(){}, method2: function(){} }
The prototype is an object so all seems right and of course the methods will work but the constructor property will be “broken”. Let’s check it:
(new MyType()).constructor === MyType // false (new MyType()).constructor === Object // true
I think the constructor property was intended to be “MyType”; what happens there is the same to write this:
var MyType = function(){}, methods = {}; MyType.prototype.constructor === MyType; // true MyType.prototype.constructor === Object; // false methods.constructor === Object; // true methods.method1 = function(){}; methods.method2 = function(){}; MyType.prototype = methods; // here happens the change... MyType.prototype.constructor === MyType; // false MyType.prototype.constructor === Object; // true
Is the constructor property always the function instantiated with the new operator?
A quick example to check it:
var MyType = function(){alert("MyType")}, OneMoreType = function(){alert("OneMoreType")}; MyType.prototype.constructor = OneMoreType; var test = new MyType(); // alerts "MyType" test.constructor === OneMoreType; // true test instanceof MyType; // true test instanceof OneMoreType; // false
The function instantiated (and executed) is MyType but the constructor property refers to OneMoreType.
That means: you can reassign the constructor property to a different function. That doesn’t change the code executed calling that function or the function’s prototype!
In other words: the constructor property of a constructor function could not be the constructor function itself (but it is by default and it is intended to be).
Manually assign the constructor property
We have just seen that is possible to manually assign the constructor property, sometimes it can be useful. Think about a situation like this:
var MyType = function(){}, methods = {}; methods.constructor === Object; // true methods.method1 = function(){}; methods.method2 = function(){}; methods.constructor = MyType; MyType.prototype = methods;
The object methods will be the prototype of the function MyType and we want to keep the original constructor property of the function (it is MyType of course). Let’s check the result:
(new MyType()).constructor === MyType // true (new MyType()).constructor === Object // false
It works: so we can say that it is something good, to manually set the constructor and make it as intended? I don’t think so: this approach changes the constructor’s “enum flag value”. It is easier to explain that with an example:
var methods = {}; methods.constructor === Object; // true // you are going to get 0 alert from here for(var property in methods){ alert(property); } methods.constructor = function(){}; // you get one alert here: it says "constructor" for(var property in methods){ alert(property); }
What that means? It means that, as default, constructor is not an enumerable property but, changing it manually, makes of it an enumerable property.
How much bad is that? Up to you answer it. Always keep in mind you will be able to make your code handles this situation but what about code is not from you?
Conclusions
The role of a constructor function is obvious but what about the rule of the constructor property? The constructor property of an object is a writeable property intended to refer to the constructor function.
Foot notes
There is a relationship between the instanceof operator and the constructor property?
Let’s check it with a quick example:
var MyType = function(){alert("MyType")}, OneMoreType = function(){alert("OneMoreType")}; MyType.prototype.constructor = OneMoreType; var test = new MyType(); // alerts "MyType" test.constructor === OneMoreType; // true test instanceof MyType; // true test instanceof OneMoreType; // false
I have already used that example inside the post but i think it is a good example for this situation; as you can see, instanceof doesn’t dipend from the constructor.
Some links
- http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
- http://pivotallabs.com/users/pjaros/blog/articles/1368-javascript-constructors-prototypes-and-the-new-keyword
- http://skilldrick.co.uk/2011/09/understanding-typeof-instanceof-and-constructor-in-javascript/
- http://www.w3schools.com/jsref/jsref_constructor_math.asp
- http://helephant.com/2008/09/14/constructor-functions/
Thanks for reading!