122

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 significance of the constructor property, as I can't seem to make it have any effect. E.g.:

function Foo(age) {
    this.age = age;
}

function Bar() {
    Foo.call(this, 42);
    this.name = "baz"; 
}

Bar.prototype = Object.create(Foo.prototype); 
var b = new Bar;    

alert(b.constructor); // "Foo". That's OK because we inherit `Foo`'s prototype.
alert(b.name);        // "baz". Shows that Bar() was called as constructor.
alert(b.age);         // "42", inherited from `Foo`.

In the above example, the object b seems to have had the right constructor called (Bar) – and it inherits the age property from Foo. So why do many people suggest this as a necessary step:

Bar.prototype.constructor = Bar;

Clearly, the right Bar constructor was called when constructing b, so what impact does this prototype property have? I am curious to know what practical difference it actually makes to have the constructor property set 'correctly'—as I can't see it having any affect on which constructor is actually called after an object is created.

Gras Double
  • 15,901
  • 8
  • 56
  • 54
aaa90210
  • 11,295
  • 13
  • 51
  • 88

6 Answers6

100

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 Fooit 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.

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
Jakob
  • 24,154
  • 8
  • 46
  • 57
  • 1
    I agree that the `constructor` property is not very useful, but inheriting from another object's prototype can be extremely powerful and I wouldn't discourage that at all. – Tim Down Oct 25 '10 at 09:38
  • Thanks - it may not be idiomatic but many of the tutorials on the net (and q/a's on SE) suggest using this particular method is 'needed' - as if the whole prototype model breaks if you don't use it. – aaa90210 Oct 25 '10 at 09:47
  • 1
    Oh, sorry if that's how it came through. Inheriting from another objects prototype is not the problem; altering the constructor-property is. – Jakob Oct 25 '10 at 09:49
  • Is `__proto__` cross-browser? – Camilo Martin Sep 22 '12 at 11:43
  • If you look at `goog.inherits` in https://code.google.com/p/closure-library/source/browse/closure/goog/base.js, you'll see it right there: `childCtor.prototype.constructor = childCtor;` I think this makes sense, because to me it's unexpected that you'd have `var b = new B()` and then **not** `b.constructor === B`. What am I missing? – Dmitry Minkovsky Mar 08 '13 at 05:49
  • 5
    @Jakob, you say "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`." This is not correct. The `constructor` property refers to the function that created a given object's **prototype**, as seen in the example even by the OP. – Behrang Jun 11 '13 at 16:11
  • 1
    "you can look at it to see which function was used in conjunction with the operator new to create your object". No, you can't. It provides a hint as to the function a prototype object was first related too (provided the *constructor* property hasn't been set to some other value). It tells you nothing for certain about the instance that inherits it. – RobG May 20 '14 at 02:10
  • Many, many years after it was originally written, *"The `constructor` property does not cause any particular effects in your program"* is no longer true. `constructor` is now used for operations in the JavaScript specification, such as [here](https://tc39.es/ecma262/#sec-speciesconstructor), [here](https://tc39.es/ecma262/#sec-arrayspeciescreate), [here](https://tc39.es/ecma262/#sec-regexp-pattern-flags), and [here](https://tc39.es/ecma262/#sec-promise-resolve). – T.J. Crowder Sep 02 '20 at 15:14
72

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.

Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • The `constructor` is an important part of being able to shim `Object.getPrototypeOf`. I personally use `Object.getPrototypeOf` and assume everyone doesn't break the `prototype` <-> `constructor` relationship – Raynos Apr 12 '12 at 21:14
  • @Raynos: Not the safest assumption, but probably safer than it used to be. Go back a few years and nearly all the JavaScript object inheritance tutorials on the web were Java-influenced and recommended manually setting the `constructor` property. You and I have quite different ethoses: I much prefer wrappers to shims, and have lived without `Object.getPrototypeOf` for so long that I have no burning desire for it now. – Tim Down Apr 12 '12 at 22:06
  • 1
    The main point is that we should warn people that for ES5 compliance this relationship shouldn't be broken in older browsers – Raynos Apr 12 '12 at 22:26
  • 2
    @Raynos: I think I'd consider relying on the `constructor` property, which as discussed has a history of being meddled with in scripts and is otherwise of no use, an unacceptable requirement for any shim and wouldn't recommend using it in general. – Tim Down Apr 12 '12 at 22:39
  • @Raynos: We should be having these discussions in chat, but it's a timesuck. – Tim Down Apr 12 '12 at 22:41
  • @TimDown asynchronous converations in chat.SO through pings work effectively, or emails also work effectively. The main issue here is that this relationship is a crucial part of the understand that `constructor` and `prototype` are two sides of the same coin, this relationship shouldn't be broken – Raynos Apr 12 '12 at 23:02
  • Many, many years after it was originally written, your first sentence is no longer true. `constructor` is now used for operations in the JavaScript specification, such as [here](https://tc39.es/ecma262/#sec-speciesconstructor), [here](https://tc39.es/ecma262/#sec-arrayspeciescreate), [here](https://tc39.es/ecma262/#sec-regexp-pattern-flags), and [here](https://tc39.es/ecma262/#sec-promise-resolve). – T.J. Crowder Sep 02 '20 at 15:12
  • 1
    @T.J.Crowder: Well well well. I haven't been following the latest language revisions. I don't think I've ever had a use for `constructor` anyway. Thanks for the update, I'll add a note to the answer. – Tim Down Sep 02 '20 at 15:38
10

one case to use constructor:

  1. 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;
        ...
    };
    
  2. 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.

Camilo Martin
  • 37,236
  • 20
  • 111
  • 154
Jack Hu
  • 119
  • 1
  • 7
  • 1
    Yes but you can write `SubClass.superClass.call(this);`. – Ali Shakiba Apr 08 '15 at 11:34
  • Unless you plan to reference the constructor property on the instance, you can safely comment the `p.constructor = this` line and nothing changes. The answer might demonstrate the case *when* the `constructor` property is used, but it does not explain *why* it is used there. In short this answer does not answer the original question about significance of the `constructor` property. – golem Jan 21 '16 at 20:13
  • 1. Can you please code a simple usage example? 2. What is the role of `override`? – OfirD Nov 09 '16 at 09:51
5

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.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
2

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.
golem
  • 1,820
  • 1
  • 20
  • 25
  • 1
    Why didn't you prefer `Object.setPrototypeOf(BMW.prototype, Car.prototype);` instead of `BMW.prototype = Object.create(Car.prototype);`? – overexchange Oct 30 '17 at 05:41
  • @overexchange Yeah, that would reduce setting constructor step. We should use that right?? – Suraj Jain Apr 15 '19 at 14:59
0

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'
jsbisht
  • 9,079
  • 7
  • 50
  • 55