Oct 13, 2009

Does it matter for an object to know its constructor?

We all knows that javascript inherit the functionality from its constructor. It is important to understand the concept every object has a secret link to constructor's prototype. How about constructor? Does a object know who is its constructor? Let's see a simple example

function Person() {
  alert(this.constructor.name); //Person
  this.constructor.count++; // reuse its constructor as a name space to prevent name polution
};

Person.count = 0;

var p = new Person();
alert(p.constructor == Person); //true
alert(Person.count); //1

We know that constructor is also an object, (an object is not necessarily a constructor), in our case we reuse the constructor as namespace or object. And the Id is this last count. Here Person's prototype is created by Person function automatically which is essentially an {}, an empty object, so the reflection shows that Person is the constructor of p. However, if we explicitly assign a prototype to Person function. Something strange happens

function Person() {
  alert(this.constructor.name); //Person
  this.constructor.count++; // reuse its constructor as a name space to prevent name polution
};

Person.count = 0;
Object.count = 0;
Person.prototype = {};

var p = new Person();
alert(p.constructor == Person); //false, it is Object
alert(Person.count); //0
alert(Object.count); //1

Suddenly the reflection shows, the object became constructor. Why? We need to have deeper understand how constructor works. When an object is created by using "new Person()", the Person function finds that it does has no explicit prototype, then it create one explicitly, so the refection shows that Person is the constructor. But if Person finds it has an explicit prototype, it use that prototype, and the constructor of that prototype in our case is Object, reflection mechanism report that constructor is the constructor of newly created object. According to ECMAScript Language Specification Edition 3

ECMAScript supports prototype-based inheritance. Every constructor has an associated prototype,and every object created by that constructor has an implicit reference to the prototype (called the object’s prototype) associated with its constructor.

If we don't reuse constructor as name space like Person, this is does not cause any problem. If we explicitly use Person as name space, it also solves the problem.

function Person() {
  alert(Person.name); //Person
  Person.count++;
};

However, using the syntax of p.constructor.xx give you more flexibility, we can solve the problem by just adding one line, it does not change other behaviors or add other functionality

Person.prototype.constructor = Person;