5

First off, this question is not "what does the constructor property do?" - There's plenty of good documentation on exactly what it is and how it works: It's a reference to the function that created the object (which may be inherited from its prototype).

I'm more interested in knowing common use-cases for this property. It seems all good in theory, but when would you actually need a reference to the function that constructed your object? A few ideas would be:

  • Perhaps I want to clone it. I could call the constructor again and
    get another instance of my object. This of course wouldn't work well since you'd potentially be creating an instance of your object's
    prototype, not the object itself; plus a much preferred method would be to create a new object and set that object's prototype instead.
  • Perhaps you can use it to figure out what the "type" of the object is. This seems rather odd, since you can use instanceof or Object.prototype.toString() instead.
  • Can you change or re-assign the constructor? Would there ever be a good reason to do this?

Hopefully some people can chime in with some good Javascript paterns that make use of the constructor reference, or provide an official explanation for why the property exists.

Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
  • 1
    `Object.prototype.toString` won't help you determine the type of an object created via a user defined constructor. It only helps discriminate between various builtins. – Mike Samuel Nov 10 '11 at 01:12
  • "*This of course wouldn't work well since you'd potentially be creating an instance of your object's prototype, not the object itself*" - What do you mean? It works fine: http://jsfiddle.net/tjnuA/ – Šime Vidas Nov 10 '11 at 01:12
  • Actually I don't even know how you'd even do it - Something like `var x = new myObj.constructor()` or something? – Mike Christensen Nov 10 '11 at 01:19
  • @MikeChristensen Well yes, you can do it... That's one legitimate use-case. – Šime Vidas Nov 10 '11 at 01:20
  • Oh sorry, didn't notice your jsfiddle link - What I meant is that yes, it does work in theory (I hadn't tried it), but you're cloning the prototype, not the object. I've updated your code to demonstrate: http://jsfiddle.net/tjnuA/1/ – Mike Christensen Nov 10 '11 at 01:27
  • @Mike `Person.prototype = new Base();` is a sub-optimal hack that was used before we had `Object.create()` and that is deprecated now. The proper way to make `Person.prototype` inherit from `Base.prototype` is: `Person.prototype = Object.create( Base.prototype );`. You then add this line `Person.prototype.constructor = Person;` do reestablish the correct value (since you had to overwrite `Person.prototype` in order to redirect its implicit prototype link from `Object.prototype` to `Base.prototype`). **Live demo:** http://jsfiddle.net/tjnuA/2/ – Šime Vidas Nov 10 '11 at 01:36
  • Way cool! Of course the reason yours works and mine does not is not because you use `Object.create`, but because you explicitly set the constructor of Person to be what it "should" be. – Mike Christensen Nov 10 '11 at 01:42
  • @MikeChristensen Yes. Manually setting the `constructor` property is a mandatory operation whenever you have a user-defined "class" (e.g. `Person`) which inherits from another user-defined "class" (e.g. `Base`). There is no way around it. – Šime Vidas Nov 10 '11 at 01:46
  • one case to use constructor: http://stackoverflow.com/questions/4012998/what-it-the-significance-of-the-javascript-constructor-property/9882720#9882720 posted by jack. – Jack Hu Mar 27 '12 at 04:10

3 Answers3

4

One case where the constructor property is handy (or would be if it was reliable) is where a function needs to know the type of argument it has been passed, e.g.

function foo(arg) {
  if ( /* if arg is an array */ ) {
    // deal with array
  } else if ( /* if arg is an object */ ) {
    // deal with object
  }
}

If the above function is passed an array or object, then typeof will return object in both cases. The constructor property can be used:

  if ( arg.constructor == Array )

But that fails if the array is created in a different frame to where the test is taking place (i.e. it's Array constructor is a different object to the Array function in the scope of the test).

So if you rule out frames (or other cases where scope is an issue), then the constructor property is fine to use for this.

But that does not fix the general issue of the constructor property being writable (and therefore can be set to anything) and cases where the prototype chain is more than trivial.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • In this case is it better to test ```arg.constructor``` or ```arg.constructor.toString()```? JsHint is complaining when I use just ```Array``` or ```ImageData```. – forresto Aug 03 '12 at 14:13
  • It's a matter of working out why JSHint is complaining and working out if that is relevant to you. Javascript is very dynamic, life is easier if you set boundaries and live within them. – RobG Aug 05 '12 at 23:47
  • I've never found a reason to test the `.constructor` property this way. I generally use `instanceof` if I'm type testing because it's built-in to the language, works even if the object inherits from what you're testing and works even if the `.constructor` is not set properly. I guess the one thing testing the `.constructor` property could do is test if the leaf object type matches some type of object, but most polymorphic designs shouldn't need to know that. If it works like a "duck", then you can treat it like a "duck", even if it's been subclassed into a "Mallard". – jfriend00 Apr 20 '14 at 21:20
3

One of the good use cases is implementation of "inheritance" and "classes in javascript. Let's consider the following example:

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = new Person();

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

As you can see we've inherited Person, by reassigning Student.prototype to new Person();, but then we need to reassign constructor back to Student as we want to create instance of Student class, but not a Person.

UPDATE

Btw, more real-world example of inheritance in javascript is to use intermediate function, so Person object will not be created during definition stage:

// inherit Person
function F() {}
F.prototype = Person.prototype;
Student.prototype = new F();
Pavel Podlipensky
  • 8,201
  • 5
  • 42
  • 53
  • 1
    This: `Student.prototype = Object.create( Person.prototype );` instead of `Student.prototype = new Person();`. The latter one is broken and should be avoided. – Šime Vidas Nov 10 '11 at 01:48
  • 3
    I'm aware of prototype based inheritance in Javascript, however in your example if you comment out `Student.prototype.constructor = Student;` then the results will be exactly the same. So what's the point in "correcting" the constructor. My question is when do you even need the constructor reference in the first place? – Mike Christensen Nov 10 '11 at 01:55
  • 1
    @MikeChristensen, if you don't correct constructor, then you may not be able to recognize exact type of the object: `student1.constructor === Student //will be false if correct constructor was not assigned` Does it make sense? – Pavel Podlipensky Nov 10 '11 at 02:26
  • It appears so far the only use-case we've found is the one where you need to be able to accurately figure out what type of object something is, and you need it to work across primitive types and user-defined types. – Mike Christensen Nov 10 '11 at 02:58
  • Well, sometimes you even need to create the same instance of the object as you have. And the only way to do this is to figure out the type and then create the object, or use directly `obj.prototype.constructor` for this – Pavel Podlipensky Nov 11 '11 at 17:26
1

I've used it before for type checking. It's not much more useful than instanceof, but it's a little more explicit.

function isArray(o) {
    return o.constructor == Array;
}
gilly3
  • 87,962
  • 25
  • 144
  • 176