An object has a build-in property named constructor
. It is meant to reference the function which made the object, but it fails to do it sometimes.
Example
Let’s create a simple constructor and see how new objects have the right constructor
value:
function Rabbit() { } var rabbit = new Rabbit() alert( rabbit.constructor == Rabbit ) // true
The origins of constructor
When you declare a function:
function Rabbit() { /* ..code.. */ }
The interpreter creates the new function object from your declaration. Together with the function, it’s prototype
property is created and populated.
This default value the prototype
is an object with property constructor
, which is set to the function itself. In our case, to Rabbit
:
Rabbit.prototype = { constructor: Rabbit }
So, when new Rabbit
is called, the Rabbit.prototype
becomes __proto__
and the constructor
becomes accessible from the object:
rabbit.__proto__ == { constructor: Rabbit )
Let’s make a direct check:
function Rabbit() { } var rabbit = new Rabbit() alert( rabbit.hasOwnProperty('constructor') ) // false alert( Rabbit.prototype.hasOwnProperty('constructor') ) // true
Keeping constructor
up to date
Calling rabbit.constructor
actually returns rabbit.__proto__.constructor
.
There is a side effect. For example, let’s see what happens when we replace the prototype:
function Rabbit() { } // (1) Rabbit.prototype = {} // (2) var rabbit = new Rabbit() alert( rabbit.constructor == Object ) // true
Whops! The rabbit
lost it’s constructor.
It happened, because Rabbit.prototype
is replaced with a new Object
.
See the picture for better understanding:
In other words, when the interpreter creates a prototype
of a function, it makes an object and puts constructor
in there.
But the custom prototype {}
is an object without constructor
.
So, the interpreter falls back to it’s __proto__
, ultimately using the native Object.prototype.constructor
.
The constructor
property is assigned to function prototype
. Then the interpreter forgets about it.
Additional code is usually required to prevent it from being overwritten.
If you intent to keep it correct, then put it into the new prototype, like this:
function Rabbit() { } Rabbit.prototype = { constructor: Rabbit } var rabbit = new Rabbit() alert( rabbit.constructor == Rabbit ) // now fine
There’s the code:
var obj = new Foo(); // Foo is an arbitrary function
We need to create an object using the same constructor function.
Will the following code work right?
If yes, will it work correctly for any Foo
, or only for particular cases?
var obj2 = new obj.constructor;
From the first glance - yes, it will work.
For example:
function Foo() { this.toString = function() { return 'Foo!'; }; } var obj = new Foo(); var obj2 = new obj.constructor; alert(obj2); // Foo!
But it only works, because Foo.prototype.constructor == Foo
. So, if someone overwrites Foo.prototype
(or spoils constructor
in another way), the code would fail:
function Foo() { this.toString = function() { return 'Foo!'; }; } *!* Foo.prototype = {}; */!* var obj = new Foo(); var obj2 = new obj.constructor; alert(obj2); // [object Object]
The result is an empty literal object, because {}
is actually new Object
, with constructor == Object
.
So, obj2
gets created using the default Object
constructor instead of Foo
.
Summary
- The
constructor
property is created together with the function as a single property offunc.prototype
. - When the
prototype
is replaced, theconstructor
is lost. The interpreter doesn’t keep it. - If we want to have the right
constructor
after inheritance - we need to set it by our own.