Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it necessary to set the prototype constructor?

In the section about inheritance in the MDN article Introduction to Object Oriented Javascript, I noticed they set the prototype.constructor:

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

Does this serve any important purpose? Is it okay to omit it?

like image 903
trinth Avatar asked Dec 10 '11 02:12

trinth


People also ask

What is the use of prototype constructor in JavaScript?

constructor. The constructor property returns a reference to the Object constructor function that created the instance object. Note that the value of this property is a reference to the function itself, not a string containing the function's name.

Why do we need a constructor function?

A constructor is a special function that creates and initializes an object instance of a class. In JavaScript, a constructor gets called when an object is created using the new keyword. The purpose of a constructor is to create a new object and set values for any existing object properties.

What is the purpose of prototypes in classes?

In prototypical inheritance, prototypes are object instances to which child instances delegate undefined properties. In contrast, classes in classical inheritance are type definitions, from which child classes inherit methods and properties during instantiation.

What is the difference between constructor and prototype?

So what's the difference between constructor and prototype? A short answer is that the constructor is a function that is used to create an object, while the prototype is an object that contains properties and methods that are inherited by objects created from a constructor.


2 Answers

It's not always necessary, but it does have its uses. Suppose we wanted to make a copy method on the base Person class. Like this:

// define the Person Class   function Person(name) {     this.name = name; }    Person.prototype.copy = function() {       // return new Person(this.name); // just as bad     return new this.constructor(this.name); };    // define the Student class   function Student(name) {       Person.call(this, name); }    // inherit Person   Student.prototype = Object.create(Person.prototype); 

Now what happens when we create a new Student and copy it?

var student1 = new Student("trinth");   console.log(student1.copy() instanceof Student); // => false 

The copy is not an instance of Student. This is because (without explicit checks), we'd have no way to return a Student copy from the "base" class. We can only return a Person. However, if we had reset the constructor:

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

...then everything works as expected:

var student1 = new Student("trinth");   console.log(student1.copy() instanceof Student); // => true 
like image 124
Wayne Avatar answered Sep 27 '22 00:09

Wayne


Does this serve any important purpose?

Yes and no.

In ES5 and earlier, JavaScript itself didn't use constructor for anything. It defined that the default object on a function's prototype property would have it and that it would refer back to the function, and that was it. Nothing else in the specification referred to it at all.

That changed in ES2015 (ES6), which started using it in relation to inheritance hierarchies. For instance, Promise#then uses the constructor property of the promise you call it on (via SpeciesConstructor) when building the new promise to return. It's also involved in subtyping arrays (via ArraySpeciesCreate).

Outside of the language itself, sometimes people would use it when trying to build generic "clone" functions or just generally when they wanted to refer to what they believed would be the object's constructor function. My experience is that using it is rare, but sometimes people do use it.

Is it okay to omit it?

It's there by default, you only need to put it back when you replace the object on a function's prototype property:

Student.prototype = Object.create(Person.prototype); 

If you don't do this:

Student.prototype.constructor = Student; 

...then Student.prototype.constructor inherits from Person.prototype which (presumably) has constructor = Person. So it's misleading. And of course, if you're subclassing something that uses it (like Promise or Array) and not using class¹ (which handles this for you), you'll want to make sure you set it correctly. So basically: It's a good idea.

It's okay if nothing in your code (or library code you use) uses it. I've always ensured it was correctly wired up.

Of course, with ES2015 (aka ES6)'s class keyword, most of the time we would have used it, we don't have to anymore, because it's handled for us when we do

class Student extends Person { } 

¹ "...if you're subclassing something that uses it (like Promise or Array) and not using class..." — It's possible to do that, but it's a real pain (and a bit silly). You have to use Reflect.construct.

like image 23
T.J. Crowder Avatar answered Sep 24 '22 00:09

T.J. Crowder