What Is the 'Constructor' Property Really Used For

What is the `constructor` property really used for?

I can't really see why the constructor property is what it is in JS. I occasionally find myself using it to get to the prototypes of objects (like the Event object) in IE < 9. However I do think it's there to allow some ppl to mimic classical OO programming constructs:

function Foo()
{
this.name = 'Foo';
}
function Bar()
{
this.name = 'Bar';
}
function Foobar(){};
Foo.prototype = new Foobar;
Foo.prototype.constructor = Foo;
Bar.prototype = new Foobar;
Bar.prototype.constructor = Bar;
var foo = new Foo();
var bar = new Bar();
//so far the set-up
function pseudoOverload(obj)
{
if (!(obj instanceof Foobar))
{
throw new Error 'I only take subclasses of Foobar';
}
if (obj.constructor.name === 'Foo')
{
return new obj.constructor;//reference to constructor is quite handy
}
//do stuff with Bar instance
}

So AFAIK, the "advantages" of the constructor property are:

  • instantiating new objects from instance easily
  • being able to group your objects as being subclasses of a certain class, but still being able to check what particular type of subclass you're dealing with.
  • As you say: being tidy.

What is the significance of the Javascript constructor property?

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.

What is constructor property in Javascript?

In previous versions of ECMAScript, instanceof used the constructors in the object's prototype chain. In ES6, however, there is a Symbol that determines if an object is an instanceof a constructor, and that's more reliable since it takes a very delibarate effort to screw that Symbol.

However, an object's constructor can be useful in some cases where you want to create another object of the same type, e.g. for properly cloning an instance:

function clone(o) {
var newO = new o.constructor()
// copy properties
return newO
}

Advantages of setting the constructor Property in the prototype

It's just to properly reset the constructor property to accurately reflect the function used to construct the object.

Sub.prototype = new Super();

console.log(new Sub().constructor == Sub);
// -> 'false'

Sub.prototype.constructor = Sub;
console.log(new Sub().constructor == Sub);
// -> 'true'

Is there a good use case for the constructor property in Javascript?

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.

Why are the properties and methods created in a function not shown in the constructor property of the prototype of that function?

The code you've written doesn't add anything to the prototype. Instead, it adds properties to each instance. In other words, if someone calls

const a = new protoFunc('bob');

then a will have a .name and a .getName property directly on it. It doesn't get these via the prototype chain, and they don't exist before you call new.

If you want getName to be on the prototype chain, you need to change your code to this:

function protoFunc(name) {
this.name = name;
}

protoFunc.prototype.getName = function () {
return this.name;
}

Note: i changed the line in protoFunc that said this.name to this.name = name, since that's probably what you meant to do.

Javascript - why this loop ? instance-(prototype property-constructor property-function object-constructor property)

Of course it retains the instance. Why wouldn't it? If you're making a duck, it's a duck - its DNA says that it's a duck, no matter if you paint it black or teach it to be a goose.

Also, in your case, setting the constructor has no effect. When you do new func (or new func(), which are identical), you go and grab an internal property of the function (the [[Construct]] property), and not func.prototype.constructor.

obj.constructor is defined on every single object, since it's defined on every "constructor": That is, Object Number Function Date Boolean String and so on. Each have a constructor property in their prototype:

Object.prototype.constructor === Object;
String.prototype.constructor === String;
//etc

Each one has its prototype.constructor pointing to itself.

Since functions can also behave like constructors, their .prototype.constructor property points to themselves as well. AFAIK, that's unused in the language itself.

The terse, technical answer? http://es5.github.com/#x11.8.6

//foo instanceof bar
Return the result of calling the [[HasInstance]] internal method of bar with argument foo.

(slightly paraphrased)

Basically, you're asking mother-duck: "Excuse me ma'am, is this your child?" The child has little say in the matter.

Edit: As mentioned in the comments, changing the prototype does indeed affect the instanceof results. Like above, there's the intuitive answer and the technical answer.

Intuitive answer is simple: The prototype defines the object. Therefore, changing the prototype changes the DNA - you make the duck a goose, not by teaching it to be a goose, but by going to its DNA and changing it to a goose DNA.

The technicality is seeing what [[HasInstance]] does. (the other [[HasIntsance]] calls this one) The spec is really dry and terse, so here's the algorithm written in pseudo-javascript:

//assume Func is the function we're talking about
function HasInstance ( value ) {
if ( IsntAnObject(value) ) {
return false;
}

var proto = Func.prototype;

if ( Type(proto) !== "Object" ) {
return false;
}

while ( value !== null ) {
value = value.prototype;
if ( value === proto ) {
return true;
}
}
return false;
}

As can be seen, by changing the prototype, we're changing the behavior - value will be different values.



Related Topics



Leave a reply



Submit