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?
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.
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.
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.
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.
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
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With