What is the point of Javascript Constructor? - javascript

Please provide your thoughts with respect to Javascript only! I am aware of classes and classical inheritance but not at a great detail.
As far as I know, constructors are used as prototypes for other objects. For example, I could create a car constructor and give it objects such as hondaCivic, toyotaCamry, etc. Are there any other important things I should know about constructors?
Furthermore,
What is the purpose of a constructor, apart from what I have already stated?
What are the benefits / disadvantages of a constructor?

A constructor is just a normal function. There is nothing special about it inherently.
All functions have a property called prototype.
If you write
var myInstance = new MyFuction();
JavaScript does something special with your function when it executes it.
It sets the value of this inside the function body to be myInstance.
Additionally, it creates a reference to MyFunction.prototype and stores it as an internal property of myInstance.
When your code is executing, the rule that the interpreter follows is such that, if you try to access a property on myInstance that it can't find, it will follow that reference to the function's prototype and look there. This forms a chain, known as the prototype chain that leads all the way up to Object.prototype.
Here's an example:
function Dog(name, breed) {
this.name = name;
this.breed = breed;
//if you don't specify a return value, `this` will be returned
}
Dog.prototype.speak = function() {
alert('Ruff, I\'m ' + this.name + ' the talking ' + this.breed);
}
var myDog = new Dog('buttercup', 'poodle');
myDog.speak();
The snippet above works, but if you run: console.log(myDog) you'll see that it does not have a speak method. the speak method was found in it's prototype.
This means that all 'instances' of Dog that are created will all share the same speak method.
So, If I create another dog, it will be able to speak aswell:
var tommysDog = new Dog('rosco', 'pitbull');
tommysDog.speak(); //tommy's dog can speak too
function Dog(name, breed) {
this.name = name;
this.breed = breed;
//if you don't specify a return value, `this` will be returned
}
Dog.prototype.speak = function() {
alert('Ruff, I\'m ' + this.name + ' the talking ' + this.breed);
}
var myDog = new Dog('buttercup', 'poodle');
var tommysDog = new Dog('rosco', 'pitbull');
tommysDog.speak();
It also means that if I change the value of Dog.prototype.speak at run time, all instances will be affected.
Note: technically, functions do have a constructor property but it's not that important and it would just confuse you more if I tried to explain it here.
I suggest you read the mozilla docs
Additionally, I suggest you read this book. You'll learn a lot about proper design.
Also note that this is just one way to achieve code re-use. You don't have to go through prototypes at all. In fact JavaScript has methods that let you supply arbitrary values as the value of this to functions as an argument.
This means that, even though my pet lizard can't normally speak, I can just borrow the method from Dog.prototype by utilizing a method like call() or apply(). (All functions have these methods because they 'inherit' them from Function.prototype.)
function Dog(name, breed) {
this.name = name;
this.breed = breed;
//if you don't specify a return value, `this` will be returned
}
Dog.prototype.speak = function() {
alert('Ruff, I\'m ' + this.name + ' the talking ' + this.breed);
};
function Lizard(name, species) {
this.name = name;
this.species = species;
}
Lizard.prototype.speak = function() {
var pretend_dog = { name: this.name, breed: this.species };
Dog.prototype.speak.call(pretend_dog);
};
var myLizard = new Lizard('larry', 'chamelion');
myLizard.speak();

A "constructor" in Javascript is just a function which has a special property called "prototype". Most (but not all) built-in and all user-defined functions are also constructors. When you define a function, like
function Car() {}
you actually create two objects: a function and its prototype, which is an empty object by default:
The only difference between a constructor and a "non-constructor" function is that the former can be used in a new expression:
honda = new Car()
The new expression does three things:
allocate a new generic object
copy the constructor's prototype into this object's internal __proto__ property
execute the constructor body, passing the newly created object as this
This final object relationship looks like this:
Constructors start making sense when you redefine their default prototype, thus creating a prototypical inheritance chain:
function Vehicle() {}
function Car() {}
Car.prototype = new Vehicle;
honda = new Car;
Now honda inherits from Car.prototype which in turn inherits from Vehicle.prototype:

constructors are used as prototypes for other objects.
No, they are not - if you mean "inheritance target" by the term "prototype".
For example, I could create a car constructor and give it objects such as hondaCivic, toyotaCamry, etc.
Not sure what you mean. Please show code if you have questions about it.
What is the purpose of a constructor?
Not different from other languages, the purpose of a constructor function is to initialise an instance.
In JS, you can call it with the new operator to create instances (objects).
What are the benefits / disadvantages of a constructor?
It does its job. Sometimes, its the wrong tool used for the job.

Related

Javascript prototype constructor - Why should I fix it? [duplicate]

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?
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.
TLDR; Not super necessary, but will probably help in the long run, and it is more accurate to do so.
NOTE: Much edited as my previous answer was confusingly written and had some errors that I missed in my rush to answer. Thanks to those who pointed out some egregious errors.
Basically, it's to wire subclassing up correctly in Javascript. When we subclass, we have to do some funky things to make sure that the prototypal delegation works correctly, including overwriting a prototype object. Overwriting a prototype object includes the constructor, so we then need to fix the reference.
Let's quickly go through how 'classes' in ES5 work.
Let's say you have a constructor function and its prototype:
//Constructor Function
var Person = function(name, age) {
this.name = name;
this.age = age;
}
//Prototype Object - shared between all instances of Person
Person.prototype = {
species: 'human',
}
When you call the constructor to instantiate, say Adam:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
The new keyword invoked with 'Person' basically will run the Person constructor with a few additional lines of code:
function Person (name, age) {
// This additional line is automatically added by the keyword 'new'
// it sets up the relationship between the instance and the prototype object
// So that the instance will delegate to the Prototype object
this = Object.create(Person.prototype);
this.name = name;
this.age = age;
return this;
}
/* So 'adam' will be an object that looks like this:
* {
* name: 'Adam',
* age: 19
* }
*/
If we console.log(adam.species), the lookup will fail at the adam instance, and look up the prototypal chain to its .prototype, which is Person.prototype - and Person.prototype has a .species property, so the lookup will succeed at Person.prototype. It will then log 'human'.
Here, the Person.prototype.constructor will correctly point to Person.
So now the interesting part, the so-called 'subclassing'. If we want to create a Student class, that is a subclass of the Person class with some additional changes, we'll need to make sure that the Student.prototype.constructor points to Student for accuracy.
It doesn't do this by itself. When you subclass, the code looks like this:
var Student = function(name, age, school) {
// Calls the 'super' class, as every student is an instance of a Person
Person.call(this, name, age);
// This is what makes the Student instances different
this.school = school
}
var eve = new Student('Eve', 20, 'UCSF');
console.log(Student.prototype); // this will be an empty object: {}
Calling new Student() here would return an object with all of the properties we want. Here, if we check eve instanceof Person, it would return false. If we try to access eve.species, it would return undefined.
In other words, we need to wire up the delegation so that eve instanceof Person returns true and so that instances of Student delegate correctly to Student.prototype, and then Person.prototype.
BUT since we're calling it with the new keyword, remember what that invocation adds? It would call Object.create(Student.prototype), which is how we set up that delegational relationship between Student and Student.prototype. Note that right now, Student.prototype is empty. So looking up .species an instance of Student would fail as it delegates to only Student.prototype, and the .species property doesn't exist on Student.prototype.
When we do assign Student.prototype to Object.create(Person.prototype), Student.prototype itself then delegates to Person.prototype, and looking up eve.species will return human as we expect. Presumably we would want it to inherit from Student.prototype AND Person.prototype. So we need to fix all of that.
/* This sets up the prototypal delegation correctly
*so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
*This also allows us to add more things to Student.prototype
*that Person.prototype may not have
*So now a failed lookup on an instance of Student
*will first look at Student.prototype,
*and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);
Now the delegation works, but we're overwriting Student.prototype with an of Person.prototype. So if we call Student.prototype.constructor, it would point to Person instead of Student. This is why we need to fix it.
// Now we fix what the .constructor property is pointing to
Student.prototype.constructor = Student
// If we check instanceof here
console.log(eve instanceof Person) // true
In ES5, our constructor property is a reference that refers to a function that we've written with the intent to be a 'constructor'. Aside from what the new keyword gives us, the constructor is otherwise a 'plain' function.
In ES6, the constructor is now built into the way we write classes - as in, it's provided as a method when we declare a class. This is simply syntactic sugar but it does accord us some conveniences like access to a super when we are extending an existing class. So we would write the above code like this:
class Person {
// constructor function here
constructor(name, age) {
this.name = name;
this.age = age;
}
// static getter instead of a static property
static get species() {
return 'human';
}
}
class Student extends Person {
constructor(name, age, school) {
// calling the superclass constructor
super(name, age);
this.school = school;
}
}
I'd disagree. It isn't necessary to set the prototype. Take that exact same code but remove the prototype.constructor line. Does anything change? No. Now, make the following changes:
Person = function () {
this.favoriteColor = 'black';
}
Student = function () {
Person.call(this);
this.favoriteColor = 'blue';
}
and at the end of the test code...
alert(student1.favoriteColor);
The color will be blue.
A change to the prototype.constructor, in my experience, doesn't do much unless you're doing very specific, very complicated things that probably aren't good practice anyway :)
Edit:
After poking around the web for a bit and doing some experimentation, it looks like people set the constructor so that it 'looks' like the thing that is being constructed with 'new'. I guess I would argue that the problem with this is that javascript is a prototype language - there is no such thing as inheritence. But most programmers come from a background of programming that pushes inheritence as 'the way'. So we come up with all sorts of things to try and make this prototypical language a 'classic' language.. such as extending 'classes'. Really, in the example they gave, a new student is a person - it isn't 'extending' from another student.. the student is all about the person, and whatever the person is the student is as well. Extend the student, and whatever you've extended is a student at heart, but is customized to fit your needs.
Crockford is a bit crazy and overzealous, but do some serious reading on some of the stuff that he's written.. it'll make you look at this stuff very differently.
This has the huge pitfall that if you wrote
Student.prototype.constructor = Student;
but then if there was a Teacher whose prototype was also Person and you wrote
Teacher.prototype.constructor = Teacher;
then the Student constructor is now Teacher!
Edit:
You can avoid this by ensuring that you had set the Student and Teacher prototypes using new instances of the Person class created using Object.create, as in the Mozilla example.
Student.prototype = Object.create(Person.prototype);
Teacher.prototype = Object.create(Person.prototype);
So far confusion is still there.
Following the original example, as you have an existing object student1 as:
var student1 = new Student("Janet", "Applied Physics");
Suppose you don't want to know how student1 is created, you just want another object like it, you can use the constructor property of student1 like:
var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");
Here it will fail to get the properties from Student if the constructor property is not set. Rather it will create a Person object.
Got a nice code example of why it is really necessary to set the prototype constructor..
function CarFactory(name){
this.name=name;
}
CarFactory.prototype.CreateNewCar = function(){
return new this.constructor("New Car "+ this.name);
}
CarFactory.prototype.toString=function(){
return 'Car Factory ' + this.name;
}
AudiFactory.prototype = new CarFactory(); // Here's where the inheritance occurs
AudiFactory.prototype.constructor=AudiFactory; // Otherwise instances of Audi would have a constructor of Car
function AudiFactory(name){
this.name=name;
}
AudiFactory.prototype.toString=function(){
return 'Audi Factory ' + this.name;
}
var myAudiFactory = new AudiFactory('');
alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');
var newCar = myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory
alert(newCar);
/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class ).. Dont we want our new car from Audi factory ????
*/
No need for sugared function 'classes' or using 'New' these days. Use object literals.
The Object prototype is already a 'class'. When you define an object literal, it is already an instance of the prototype Object. These can also act as another object's prototype, etc.
const Person = {
name: '[Person.name]',
greeting: function() {
console.log( `My name is ${ this.name || '[Name not assigned]' }` );
}
};
// Person.greeting = function() {...} // or define outside the obj if you must
// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John
// Define new greeting method
john.greeting = function() {
console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John
// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane
// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]
This is worth a read:
Class-based object-oriented languages, such as Java and C++, are
founded on the concept of two distinct entities: classes and
instances.
...
A prototype-based language, such as JavaScript, does not make this
distinction: it simply has objects. A prototype-based language has the
notion of a prototypical object, an object used as a template from
which to get the initial properties for a new object. Any object can
specify its own properties, either when you create it or at run time.
In addition, any object can be associated as the prototype for another
object, allowing the second object to share the first object's
properties
It is necessary when you need an alternative to toString without monkeypatching:
//Local
foo = [];
foo.toUpperCase = String(foo).toUpperCase;
foo.push("a");
foo.toUpperCase();
//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);
//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();
//toString alternative via Prototype constructor
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a,b");
foo.constructor();
//toString override
var foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();
//Object prototype as a function
Math.prototype = function(char){return Math.prototype[char]};
Math.prototype.constructor = function()
{
var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
while (i < max)
{
Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
i = i + 1;
}
}
Math.prototype.constructor();
console.log(Math.prototype("a") );
console.log(Math.prototype["a"] );
console.log(Math.prototype("a") === Math.prototype["a"]);
EDIT, I was actually wrong. Commenting the line out doesn't change it's behavior at all. (I tested it)
Yes, it is necessary. When you do
Student.prototype = new Person();
Student.prototype.constructor becomes Person. Therefore, calling Student() would return an object created by Person. If you then do
Student.prototype.constructor = Student;
Student.prototype.constructor is reset back to Student. Now when you call Student() it executes Student, which calls the parent constructor Parent(), it returns the correctly inherited object. If you didn't reset Student.prototype.constructor before calling it you would get an object that would not have any of the properties set in Student().
Given simple constructor function:
function Person(){
this.name = 'test';
}
console.log(Person.prototype.constructor) // function Person(){...}
Person.prototype = { //constructor in this case is Object
sayName: function(){
return this.name;
}
}
var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}
By default (from the specification https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor), all prototypes automatically get a property called constructor that points back to the function on which it is a property.
Depending on the constructor, other properties and methods might be added to the prototype which is not a very common practice but still it is allowed for extensions.
So simply answering: we need make sure that the value in prototype.constructor is correctly set as it is supposed by the specification to be.
Do we have to always set correctly this value? It helps with debugging and makes internal structure consistent against specification. We should definitely when our API is being used by the thirdparties, but not really when the code is finally executed in the runtime.
Here's one example from MDN which I found very helpful to understand its uses.
In JavaScript, we have async functions which returns AsyncFunction object. AsyncFunction is not a global object but one may retrieve it by using constructor property and utilize it.
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
// AsyncFunction constructor
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor
var a = new AsyncFunction('a',
'b',
'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');
a(10, 20).then(v => {
console.log(v); // prints 30 after 4 seconds
});
It is necessary. Any class in class inheritance must has its own constructor, so as in prototype inheritance.It is also convenient for object construction. But the question is unnecessary and what is necessary is understanding in JavaScript world effect of calling function as constructor and rule of resolving object property.
Effect of executing function as constructor with expression new <function name>( [ parameters] )
a object whose type name is the function name is created
inner properties in the function attaches to the created object
property prototype of the function attaches automatically to the created object as prototype
Rule of resolving property of object
The property will not only be sought on the object but on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.
Basing on these underlying mechanisms, statement <constructor name>.prototype.constructor = <constructor name> equals in term of effect to attach constructor in constructor body with expression this.constructor = <constructor name>. The constructor will be resolved on the object if second utterance while on object's prototype if first utterance.
It is not necessary. It is just one of the many things traditional, OOP champions do to try to turn JavaScript's prototypical inheritance into classical inheritance. The only thing that the following
Student.prototype.constructor = Student;
does, is that you now have a reference of the current "constructor".
In Wayne's answer, that has been marked as correct, you could the exact same thing that the following code does
Person.prototype.copy = function() {
// return new Person(this.name); // just as bad
return new this.constructor(this.name);
};
with the code below (just replace this.constructor with Person)
Person.prototype.copy = function() {
// return new Person(this.name); // just as bad
return new Person(this.name);
};
Thank God that with ES6 classical inheritance purists can use language's native operators like class, extends and super and we don't have to see like prototype.constructor corrections and parent refereces.

Inheritance using Object.create [duplicate]

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?
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.
TLDR; Not super necessary, but will probably help in the long run, and it is more accurate to do so.
NOTE: Much edited as my previous answer was confusingly written and had some errors that I missed in my rush to answer. Thanks to those who pointed out some egregious errors.
Basically, it's to wire subclassing up correctly in Javascript. When we subclass, we have to do some funky things to make sure that the prototypal delegation works correctly, including overwriting a prototype object. Overwriting a prototype object includes the constructor, so we then need to fix the reference.
Let's quickly go through how 'classes' in ES5 work.
Let's say you have a constructor function and its prototype:
//Constructor Function
var Person = function(name, age) {
this.name = name;
this.age = age;
}
//Prototype Object - shared between all instances of Person
Person.prototype = {
species: 'human',
}
When you call the constructor to instantiate, say Adam:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
The new keyword invoked with 'Person' basically will run the Person constructor with a few additional lines of code:
function Person (name, age) {
// This additional line is automatically added by the keyword 'new'
// it sets up the relationship between the instance and the prototype object
// So that the instance will delegate to the Prototype object
this = Object.create(Person.prototype);
this.name = name;
this.age = age;
return this;
}
/* So 'adam' will be an object that looks like this:
* {
* name: 'Adam',
* age: 19
* }
*/
If we console.log(adam.species), the lookup will fail at the adam instance, and look up the prototypal chain to its .prototype, which is Person.prototype - and Person.prototype has a .species property, so the lookup will succeed at Person.prototype. It will then log 'human'.
Here, the Person.prototype.constructor will correctly point to Person.
So now the interesting part, the so-called 'subclassing'. If we want to create a Student class, that is a subclass of the Person class with some additional changes, we'll need to make sure that the Student.prototype.constructor points to Student for accuracy.
It doesn't do this by itself. When you subclass, the code looks like this:
var Student = function(name, age, school) {
// Calls the 'super' class, as every student is an instance of a Person
Person.call(this, name, age);
// This is what makes the Student instances different
this.school = school
}
var eve = new Student('Eve', 20, 'UCSF');
console.log(Student.prototype); // this will be an empty object: {}
Calling new Student() here would return an object with all of the properties we want. Here, if we check eve instanceof Person, it would return false. If we try to access eve.species, it would return undefined.
In other words, we need to wire up the delegation so that eve instanceof Person returns true and so that instances of Student delegate correctly to Student.prototype, and then Person.prototype.
BUT since we're calling it with the new keyword, remember what that invocation adds? It would call Object.create(Student.prototype), which is how we set up that delegational relationship between Student and Student.prototype. Note that right now, Student.prototype is empty. So looking up .species an instance of Student would fail as it delegates to only Student.prototype, and the .species property doesn't exist on Student.prototype.
When we do assign Student.prototype to Object.create(Person.prototype), Student.prototype itself then delegates to Person.prototype, and looking up eve.species will return human as we expect. Presumably we would want it to inherit from Student.prototype AND Person.prototype. So we need to fix all of that.
/* This sets up the prototypal delegation correctly
*so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
*This also allows us to add more things to Student.prototype
*that Person.prototype may not have
*So now a failed lookup on an instance of Student
*will first look at Student.prototype,
*and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);
Now the delegation works, but we're overwriting Student.prototype with an of Person.prototype. So if we call Student.prototype.constructor, it would point to Person instead of Student. This is why we need to fix it.
// Now we fix what the .constructor property is pointing to
Student.prototype.constructor = Student
// If we check instanceof here
console.log(eve instanceof Person) // true
In ES5, our constructor property is a reference that refers to a function that we've written with the intent to be a 'constructor'. Aside from what the new keyword gives us, the constructor is otherwise a 'plain' function.
In ES6, the constructor is now built into the way we write classes - as in, it's provided as a method when we declare a class. This is simply syntactic sugar but it does accord us some conveniences like access to a super when we are extending an existing class. So we would write the above code like this:
class Person {
// constructor function here
constructor(name, age) {
this.name = name;
this.age = age;
}
// static getter instead of a static property
static get species() {
return 'human';
}
}
class Student extends Person {
constructor(name, age, school) {
// calling the superclass constructor
super(name, age);
this.school = school;
}
}
I'd disagree. It isn't necessary to set the prototype. Take that exact same code but remove the prototype.constructor line. Does anything change? No. Now, make the following changes:
Person = function () {
this.favoriteColor = 'black';
}
Student = function () {
Person.call(this);
this.favoriteColor = 'blue';
}
and at the end of the test code...
alert(student1.favoriteColor);
The color will be blue.
A change to the prototype.constructor, in my experience, doesn't do much unless you're doing very specific, very complicated things that probably aren't good practice anyway :)
Edit:
After poking around the web for a bit and doing some experimentation, it looks like people set the constructor so that it 'looks' like the thing that is being constructed with 'new'. I guess I would argue that the problem with this is that javascript is a prototype language - there is no such thing as inheritence. But most programmers come from a background of programming that pushes inheritence as 'the way'. So we come up with all sorts of things to try and make this prototypical language a 'classic' language.. such as extending 'classes'. Really, in the example they gave, a new student is a person - it isn't 'extending' from another student.. the student is all about the person, and whatever the person is the student is as well. Extend the student, and whatever you've extended is a student at heart, but is customized to fit your needs.
Crockford is a bit crazy and overzealous, but do some serious reading on some of the stuff that he's written.. it'll make you look at this stuff very differently.
This has the huge pitfall that if you wrote
Student.prototype.constructor = Student;
but then if there was a Teacher whose prototype was also Person and you wrote
Teacher.prototype.constructor = Teacher;
then the Student constructor is now Teacher!
Edit:
You can avoid this by ensuring that you had set the Student and Teacher prototypes using new instances of the Person class created using Object.create, as in the Mozilla example.
Student.prototype = Object.create(Person.prototype);
Teacher.prototype = Object.create(Person.prototype);
So far confusion is still there.
Following the original example, as you have an existing object student1 as:
var student1 = new Student("Janet", "Applied Physics");
Suppose you don't want to know how student1 is created, you just want another object like it, you can use the constructor property of student1 like:
var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");
Here it will fail to get the properties from Student if the constructor property is not set. Rather it will create a Person object.
Got a nice code example of why it is really necessary to set the prototype constructor..
function CarFactory(name){
this.name=name;
}
CarFactory.prototype.CreateNewCar = function(){
return new this.constructor("New Car "+ this.name);
}
CarFactory.prototype.toString=function(){
return 'Car Factory ' + this.name;
}
AudiFactory.prototype = new CarFactory(); // Here's where the inheritance occurs
AudiFactory.prototype.constructor=AudiFactory; // Otherwise instances of Audi would have a constructor of Car
function AudiFactory(name){
this.name=name;
}
AudiFactory.prototype.toString=function(){
return 'Audi Factory ' + this.name;
}
var myAudiFactory = new AudiFactory('');
alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');
var newCar = myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory
alert(newCar);
/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class ).. Dont we want our new car from Audi factory ????
*/
No need for sugared function 'classes' or using 'New' these days. Use object literals.
The Object prototype is already a 'class'. When you define an object literal, it is already an instance of the prototype Object. These can also act as another object's prototype, etc.
const Person = {
name: '[Person.name]',
greeting: function() {
console.log( `My name is ${ this.name || '[Name not assigned]' }` );
}
};
// Person.greeting = function() {...} // or define outside the obj if you must
// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John
// Define new greeting method
john.greeting = function() {
console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John
// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane
// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]
This is worth a read:
Class-based object-oriented languages, such as Java and C++, are
founded on the concept of two distinct entities: classes and
instances.
...
A prototype-based language, such as JavaScript, does not make this
distinction: it simply has objects. A prototype-based language has the
notion of a prototypical object, an object used as a template from
which to get the initial properties for a new object. Any object can
specify its own properties, either when you create it or at run time.
In addition, any object can be associated as the prototype for another
object, allowing the second object to share the first object's
properties
It is necessary when you need an alternative to toString without monkeypatching:
//Local
foo = [];
foo.toUpperCase = String(foo).toUpperCase;
foo.push("a");
foo.toUpperCase();
//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);
//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();
//toString alternative via Prototype constructor
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a,b");
foo.constructor();
//toString override
var foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();
//Object prototype as a function
Math.prototype = function(char){return Math.prototype[char]};
Math.prototype.constructor = function()
{
var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
while (i < max)
{
Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
i = i + 1;
}
}
Math.prototype.constructor();
console.log(Math.prototype("a") );
console.log(Math.prototype["a"] );
console.log(Math.prototype("a") === Math.prototype["a"]);
EDIT, I was actually wrong. Commenting the line out doesn't change it's behavior at all. (I tested it)
Yes, it is necessary. When you do
Student.prototype = new Person();
Student.prototype.constructor becomes Person. Therefore, calling Student() would return an object created by Person. If you then do
Student.prototype.constructor = Student;
Student.prototype.constructor is reset back to Student. Now when you call Student() it executes Student, which calls the parent constructor Parent(), it returns the correctly inherited object. If you didn't reset Student.prototype.constructor before calling it you would get an object that would not have any of the properties set in Student().
Given simple constructor function:
function Person(){
this.name = 'test';
}
console.log(Person.prototype.constructor) // function Person(){...}
Person.prototype = { //constructor in this case is Object
sayName: function(){
return this.name;
}
}
var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}
By default (from the specification https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor), all prototypes automatically get a property called constructor that points back to the function on which it is a property.
Depending on the constructor, other properties and methods might be added to the prototype which is not a very common practice but still it is allowed for extensions.
So simply answering: we need make sure that the value in prototype.constructor is correctly set as it is supposed by the specification to be.
Do we have to always set correctly this value? It helps with debugging and makes internal structure consistent against specification. We should definitely when our API is being used by the thirdparties, but not really when the code is finally executed in the runtime.
Here's one example from MDN which I found very helpful to understand its uses.
In JavaScript, we have async functions which returns AsyncFunction object. AsyncFunction is not a global object but one may retrieve it by using constructor property and utilize it.
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
// AsyncFunction constructor
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor
var a = new AsyncFunction('a',
'b',
'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');
a(10, 20).then(v => {
console.log(v); // prints 30 after 4 seconds
});
It is necessary. Any class in class inheritance must has its own constructor, so as in prototype inheritance.It is also convenient for object construction. But the question is unnecessary and what is necessary is understanding in JavaScript world effect of calling function as constructor and rule of resolving object property.
Effect of executing function as constructor with expression new <function name>( [ parameters] )
a object whose type name is the function name is created
inner properties in the function attaches to the created object
property prototype of the function attaches automatically to the created object as prototype
Rule of resolving property of object
The property will not only be sought on the object but on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.
Basing on these underlying mechanisms, statement <constructor name>.prototype.constructor = <constructor name> equals in term of effect to attach constructor in constructor body with expression this.constructor = <constructor name>. The constructor will be resolved on the object if second utterance while on object's prototype if first utterance.
It is not necessary. It is just one of the many things traditional, OOP champions do to try to turn JavaScript's prototypical inheritance into classical inheritance. The only thing that the following
Student.prototype.constructor = Student;
does, is that you now have a reference of the current "constructor".
In Wayne's answer, that has been marked as correct, you could the exact same thing that the following code does
Person.prototype.copy = function() {
// return new Person(this.name); // just as bad
return new this.constructor(this.name);
};
with the code below (just replace this.constructor with Person)
Person.prototype.copy = function() {
// return new Person(this.name); // just as bad
return new Person(this.name);
};
Thank God that with ES6 classical inheritance purists can use language's native operators like class, extends and super and we don't have to see like prototype.constructor corrections and parent refereces.

How do i call 'f.prototype' correctly?

Given a javascript function
var f = function();
as far as i understand, i would call Object.getProtoypeOf(f) "f's prototype".
What is the correct term for f.prototype?
"The Prototype objects constructed with f as constructor will get" sounds a little verbose ;)
Check this out here: http://jsfiddle.net/UCmW8/
var Person = function(name) {
this.name = name;
}
Person.prototype.sayHi = function() {
alert(this.name + ' says hi!');
};
var matt = new Person('Matt');
matt.sayHi() // alerts 'Matt says hi!'
console.log('matt.prototype', matt.prototype);
console.log('Object.getPrototypeOf(matt)', Object.getPrototypeOf(matt));
console.log('Person.prototype', Person.prototype);
console.log('Object.getPrototypeOf(Person)', Object.getPrototypeOf(Person));
What does this produce?
First matt.prototype is undefined. Functions have a prototype object, and when that function used as a constructor, instances get to use properties of it, but the instances don't have a prototype property themselves.
Object.getPrototypeOf(matt) finds the real prototype. And as you can see, this is the same as Person.prototype. It allows you to get the prototype, without having a reference to the constructing function.
Lastly, if we try Object.getPrototypeOf(Person) we get something weird. Our constructor function, is a function after all. Think of functions you create as instances of some Function constructor, with it's own prototype. So you are fetching the prototype object of all functions when you do this.

Instancing new objects in javascript

I'm probably missing something really basic on javascript knowledge, but why doesn't this work?
var person = {
name:"",
age:0,
set : function(name,age){
this.name = name;
this.age = age;
}
}
var me = new person; // ERROR: Object doesn't support this action!
me.set('Victor',12);
me.name //Victor
But this does:
var person = function(){
this.name="";
this.age=0;
this.set = function(name,age){
this.name=name;
this.age=age;
}
}
var me = new person(); //WORKS!
me.set('Victor',12);
me.name; //Victor
Your first example was an object literal:
var person = {
name: "Bob",
//etc
};
You've created a single object called person, and that's that. The concept of creating new persons has no meaning.
If you want to create something that can be used to create more objects at will, you'd use a function, like your second example.
Note though that functions intended to be used as a constructor start with a capital letter by convention. Also note that when you set a function inside of your constructor using
this.functionName = function() .....
this creates a privileged function, since it has access to both public, and private members. If this set function only needs access to public properties, it would usually be added to the function's prototype. Here's how the whole thing might look
function Person() {
this.name = "";
this.age = 0;
};
Person.prototype.set = function(name,age) {
this.name = name;
this.age = age;
}
And here's what a privileged method might look like
function Person() {
var localData = "Hello";
this.showPrivateData = function() {
alert(localData);
};
this.name="";
this.age=0;
};
localData is local to the Person function, and cannot be accessed as a property on instances of Person; however, the showPrivateData function, and any other privileged functions you might add, would form a closure over it, and have access to it.
Finally, note that constructor functions can take parameters:
function Person(name, age) {
this.name= name;
this.age= age;
};
You answer your own question. A constructor (the thing that goes next to new) must be a function in JavaScript.
JavaScript has no classes (although you can simulate them), this is why. And new works only on functions (in this case it creates special variable this inside function, which is being returned implicitly after function call).
So, when using this:
var person = {
name:"",
age:0,
set : function(name,age){
this.name = name;
this.age = age;
}
};
you already create an object (which has a function as one of its properties).
But when you use this:
var person = function(){
this.name="";
this.age=0;
this.set = function(name,age){
this.name=name;
this.age=age;
}
};
you only create function, that returns this with all assigned properties when the function is called with new.
What documentation says
As documentation of new operator on Mozilla Developer Network says:
The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.
...
Creating a user-defined object requires two steps:
Define the object type by writing a function.
Create an instance of the object with new.
and you basically make both steps in the second case.
The first version uses an object literal to create a single object instance which is assigned to person. This cannot be used like a constructor with new to create other objects from person.
The second version uses a function, which can be called as a constructor to create new objects with new person().
That's just the way new works in JavaScript. Essentially if you want to be able to create multiple instances from a template (similar to how classes work in other languages) then use the new FunctionName() syntax. If you only need to create a single instance of a particular object you can use the first syntax.
Note that in the first version you can say:
person.set('Victor',12);
alert(person.name); // 'Victor'
Note also that if you are creating a function that is intended for use as a constructor the convention is to use uppercase for the first letter of its name (or the first letter of each word in the name).

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?
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.
TLDR; Not super necessary, but will probably help in the long run, and it is more accurate to do so.
NOTE: Much edited as my previous answer was confusingly written and had some errors that I missed in my rush to answer. Thanks to those who pointed out some egregious errors.
Basically, it's to wire subclassing up correctly in Javascript. When we subclass, we have to do some funky things to make sure that the prototypal delegation works correctly, including overwriting a prototype object. Overwriting a prototype object includes the constructor, so we then need to fix the reference.
Let's quickly go through how 'classes' in ES5 work.
Let's say you have a constructor function and its prototype:
//Constructor Function
var Person = function(name, age) {
this.name = name;
this.age = age;
}
//Prototype Object - shared between all instances of Person
Person.prototype = {
species: 'human',
}
When you call the constructor to instantiate, say Adam:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
The new keyword invoked with 'Person' basically will run the Person constructor with a few additional lines of code:
function Person (name, age) {
// This additional line is automatically added by the keyword 'new'
// it sets up the relationship between the instance and the prototype object
// So that the instance will delegate to the Prototype object
this = Object.create(Person.prototype);
this.name = name;
this.age = age;
return this;
}
/* So 'adam' will be an object that looks like this:
* {
* name: 'Adam',
* age: 19
* }
*/
If we console.log(adam.species), the lookup will fail at the adam instance, and look up the prototypal chain to its .prototype, which is Person.prototype - and Person.prototype has a .species property, so the lookup will succeed at Person.prototype. It will then log 'human'.
Here, the Person.prototype.constructor will correctly point to Person.
So now the interesting part, the so-called 'subclassing'. If we want to create a Student class, that is a subclass of the Person class with some additional changes, we'll need to make sure that the Student.prototype.constructor points to Student for accuracy.
It doesn't do this by itself. When you subclass, the code looks like this:
var Student = function(name, age, school) {
// Calls the 'super' class, as every student is an instance of a Person
Person.call(this, name, age);
// This is what makes the Student instances different
this.school = school
}
var eve = new Student('Eve', 20, 'UCSF');
console.log(Student.prototype); // this will be an empty object: {}
Calling new Student() here would return an object with all of the properties we want. Here, if we check eve instanceof Person, it would return false. If we try to access eve.species, it would return undefined.
In other words, we need to wire up the delegation so that eve instanceof Person returns true and so that instances of Student delegate correctly to Student.prototype, and then Person.prototype.
BUT since we're calling it with the new keyword, remember what that invocation adds? It would call Object.create(Student.prototype), which is how we set up that delegational relationship between Student and Student.prototype. Note that right now, Student.prototype is empty. So looking up .species an instance of Student would fail as it delegates to only Student.prototype, and the .species property doesn't exist on Student.prototype.
When we do assign Student.prototype to Object.create(Person.prototype), Student.prototype itself then delegates to Person.prototype, and looking up eve.species will return human as we expect. Presumably we would want it to inherit from Student.prototype AND Person.prototype. So we need to fix all of that.
/* This sets up the prototypal delegation correctly
*so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
*This also allows us to add more things to Student.prototype
*that Person.prototype may not have
*So now a failed lookup on an instance of Student
*will first look at Student.prototype,
*and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);
Now the delegation works, but we're overwriting Student.prototype with an of Person.prototype. So if we call Student.prototype.constructor, it would point to Person instead of Student. This is why we need to fix it.
// Now we fix what the .constructor property is pointing to
Student.prototype.constructor = Student
// If we check instanceof here
console.log(eve instanceof Person) // true
In ES5, our constructor property is a reference that refers to a function that we've written with the intent to be a 'constructor'. Aside from what the new keyword gives us, the constructor is otherwise a 'plain' function.
In ES6, the constructor is now built into the way we write classes - as in, it's provided as a method when we declare a class. This is simply syntactic sugar but it does accord us some conveniences like access to a super when we are extending an existing class. So we would write the above code like this:
class Person {
// constructor function here
constructor(name, age) {
this.name = name;
this.age = age;
}
// static getter instead of a static property
static get species() {
return 'human';
}
}
class Student extends Person {
constructor(name, age, school) {
// calling the superclass constructor
super(name, age);
this.school = school;
}
}
I'd disagree. It isn't necessary to set the prototype. Take that exact same code but remove the prototype.constructor line. Does anything change? No. Now, make the following changes:
Person = function () {
this.favoriteColor = 'black';
}
Student = function () {
Person.call(this);
this.favoriteColor = 'blue';
}
and at the end of the test code...
alert(student1.favoriteColor);
The color will be blue.
A change to the prototype.constructor, in my experience, doesn't do much unless you're doing very specific, very complicated things that probably aren't good practice anyway :)
Edit:
After poking around the web for a bit and doing some experimentation, it looks like people set the constructor so that it 'looks' like the thing that is being constructed with 'new'. I guess I would argue that the problem with this is that javascript is a prototype language - there is no such thing as inheritence. But most programmers come from a background of programming that pushes inheritence as 'the way'. So we come up with all sorts of things to try and make this prototypical language a 'classic' language.. such as extending 'classes'. Really, in the example they gave, a new student is a person - it isn't 'extending' from another student.. the student is all about the person, and whatever the person is the student is as well. Extend the student, and whatever you've extended is a student at heart, but is customized to fit your needs.
Crockford is a bit crazy and overzealous, but do some serious reading on some of the stuff that he's written.. it'll make you look at this stuff very differently.
This has the huge pitfall that if you wrote
Student.prototype.constructor = Student;
but then if there was a Teacher whose prototype was also Person and you wrote
Teacher.prototype.constructor = Teacher;
then the Student constructor is now Teacher!
Edit:
You can avoid this by ensuring that you had set the Student and Teacher prototypes using new instances of the Person class created using Object.create, as in the Mozilla example.
Student.prototype = Object.create(Person.prototype);
Teacher.prototype = Object.create(Person.prototype);
So far confusion is still there.
Following the original example, as you have an existing object student1 as:
var student1 = new Student("Janet", "Applied Physics");
Suppose you don't want to know how student1 is created, you just want another object like it, you can use the constructor property of student1 like:
var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");
Here it will fail to get the properties from Student if the constructor property is not set. Rather it will create a Person object.
Got a nice code example of why it is really necessary to set the prototype constructor..
function CarFactory(name){
this.name=name;
}
CarFactory.prototype.CreateNewCar = function(){
return new this.constructor("New Car "+ this.name);
}
CarFactory.prototype.toString=function(){
return 'Car Factory ' + this.name;
}
AudiFactory.prototype = new CarFactory(); // Here's where the inheritance occurs
AudiFactory.prototype.constructor=AudiFactory; // Otherwise instances of Audi would have a constructor of Car
function AudiFactory(name){
this.name=name;
}
AudiFactory.prototype.toString=function(){
return 'Audi Factory ' + this.name;
}
var myAudiFactory = new AudiFactory('');
alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');
var newCar = myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory
alert(newCar);
/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class ).. Dont we want our new car from Audi factory ????
*/
No need for sugared function 'classes' or using 'New' these days. Use object literals.
The Object prototype is already a 'class'. When you define an object literal, it is already an instance of the prototype Object. These can also act as another object's prototype, etc.
const Person = {
name: '[Person.name]',
greeting: function() {
console.log( `My name is ${ this.name || '[Name not assigned]' }` );
}
};
// Person.greeting = function() {...} // or define outside the obj if you must
// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John
// Define new greeting method
john.greeting = function() {
console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John
// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane
// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]
This is worth a read:
Class-based object-oriented languages, such as Java and C++, are
founded on the concept of two distinct entities: classes and
instances.
...
A prototype-based language, such as JavaScript, does not make this
distinction: it simply has objects. A prototype-based language has the
notion of a prototypical object, an object used as a template from
which to get the initial properties for a new object. Any object can
specify its own properties, either when you create it or at run time.
In addition, any object can be associated as the prototype for another
object, allowing the second object to share the first object's
properties
It is necessary when you need an alternative to toString without monkeypatching:
//Local
foo = [];
foo.toUpperCase = String(foo).toUpperCase;
foo.push("a");
foo.toUpperCase();
//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);
//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();
//toString alternative via Prototype constructor
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a,b");
foo.constructor();
//toString override
var foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();
//Object prototype as a function
Math.prototype = function(char){return Math.prototype[char]};
Math.prototype.constructor = function()
{
var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
while (i < max)
{
Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
i = i + 1;
}
}
Math.prototype.constructor();
console.log(Math.prototype("a") );
console.log(Math.prototype["a"] );
console.log(Math.prototype("a") === Math.prototype["a"]);
EDIT, I was actually wrong. Commenting the line out doesn't change it's behavior at all. (I tested it)
Yes, it is necessary. When you do
Student.prototype = new Person();
Student.prototype.constructor becomes Person. Therefore, calling Student() would return an object created by Person. If you then do
Student.prototype.constructor = Student;
Student.prototype.constructor is reset back to Student. Now when you call Student() it executes Student, which calls the parent constructor Parent(), it returns the correctly inherited object. If you didn't reset Student.prototype.constructor before calling it you would get an object that would not have any of the properties set in Student().
Given simple constructor function:
function Person(){
this.name = 'test';
}
console.log(Person.prototype.constructor) // function Person(){...}
Person.prototype = { //constructor in this case is Object
sayName: function(){
return this.name;
}
}
var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}
By default (from the specification https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor), all prototypes automatically get a property called constructor that points back to the function on which it is a property.
Depending on the constructor, other properties and methods might be added to the prototype which is not a very common practice but still it is allowed for extensions.
So simply answering: we need make sure that the value in prototype.constructor is correctly set as it is supposed by the specification to be.
Do we have to always set correctly this value? It helps with debugging and makes internal structure consistent against specification. We should definitely when our API is being used by the thirdparties, but not really when the code is finally executed in the runtime.
Here's one example from MDN which I found very helpful to understand its uses.
In JavaScript, we have async functions which returns AsyncFunction object. AsyncFunction is not a global object but one may retrieve it by using constructor property and utilize it.
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
// AsyncFunction constructor
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor
var a = new AsyncFunction('a',
'b',
'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');
a(10, 20).then(v => {
console.log(v); // prints 30 after 4 seconds
});
It is necessary. Any class in class inheritance must has its own constructor, so as in prototype inheritance.It is also convenient for object construction. But the question is unnecessary and what is necessary is understanding in JavaScript world effect of calling function as constructor and rule of resolving object property.
Effect of executing function as constructor with expression new <function name>( [ parameters] )
a object whose type name is the function name is created
inner properties in the function attaches to the created object
property prototype of the function attaches automatically to the created object as prototype
Rule of resolving property of object
The property will not only be sought on the object but on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.
Basing on these underlying mechanisms, statement <constructor name>.prototype.constructor = <constructor name> equals in term of effect to attach constructor in constructor body with expression this.constructor = <constructor name>. The constructor will be resolved on the object if second utterance while on object's prototype if first utterance.
It is not necessary. It is just one of the many things traditional, OOP champions do to try to turn JavaScript's prototypical inheritance into classical inheritance. The only thing that the following
Student.prototype.constructor = Student;
does, is that you now have a reference of the current "constructor".
In Wayne's answer, that has been marked as correct, you could the exact same thing that the following code does
Person.prototype.copy = function() {
// return new Person(this.name); // just as bad
return new this.constructor(this.name);
};
with the code below (just replace this.constructor with Person)
Person.prototype.copy = function() {
// return new Person(this.name); // just as bad
return new Person(this.name);
};
Thank God that with ES6 classical inheritance purists can use language's native operators like class, extends and super and we don't have to see like prototype.constructor corrections and parent refereces.

Categories

Resources