FWIW, that code isn't quite implementing the construction chain correctly (it's calling Person more often than it should [both when creating Student.prototypeand when Student is called], and failing to set constructor).
The more correct way to create Student's prototype property, if we're going to call Parent from within Student, looks like this:
...because That way, we shouldn'tget a prototype based on callParent.prototype but without calling Parent when creating. It's an either-or: Either call StudentParent's to create Student.prototype property, because that's for when or call Parent is setting up a specific instance. We'll do that within Student. (Using a specific object as a prototype is totally fine, but don't do both. When building hierarchies with constructor functions, typically not what you want to docall the parent from the child constructor, rather than when you'recreating the child prototype. When using direct object inheritance (without constructor functions to set things up.), of course you do it the other way.
The more correct way to create Student's prototype property looks like this:
...because we shouldn't call Parent when creating Student's prototype property, because that's for when Parent is setting up a specific instance. We'll do that within Student. (Using a specific object as a prototype is totally fine, but typically not what you want to do when you're using constructor functions to set things up.)
FWIW, that code isn't quite implementing the construction chain correctly (it's calling Person more often than it should [both when creating Student.prototypeand when Student is called], and failing to set constructor).
The more correct way to create Student's prototype property, if we're going to call Parent from within Student, looks like this:
That way, we get a prototype based on Parent.prototype but without calling Parent. It's an either-or: Either call Parent to create Student.prototype, or call Parent within Student, but don't do both. When building hierarchies with constructor functions, typically you want to call the parent from the child constructor, rather than when creating the child prototype. When using direct object inheritance (without constructor functions), of course you do it the other way.
This isn'tTo explain it, first let's remember how constructor functions work in JavaScript:
function Guide(a) {
this.a = a;
}
Guide.prototype.q = "Life, the Universe, and Everything";
var g = new Guide(42);
console.log(g.q); // "Life, the Universe, and Everything"
console.log(g.a); // 42
When we do new Guide(42), the new operator creates a very good implementation of inheritancenew object and assigns it a prototype using the Guide.prototype property. Then new calls Guide, although parts ofpassing in that new object as this. Guide uses this to add properties to the new object that aren't on its prototype. Then the new expression completes and its result is the new object that it are okaycreated.
Here are those two lines explainedWhen we look at g.q, since the g object doesn't have its own property called q, the JavaScript engine looks at g's prototype, which (again) it got assigned when it was created. That prototype has a q property, and so the engine uses its value.
In contrast, when we look at g.a, the g object has its own property called a, and so the value is used directly.
With that foundation in place, let's look at Student and Parent:
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
When youwe call new Student(), within the call to Student, this is (again) the new object created by the new operator, which has Student.prototype as its underlying prototype. The line above is making sure that allBut the Parent things have been donefunction hasn't had a chance to thatdo anything with this new object. So what that line does is give Parent a chance to do whatever it needs to do to new objects that it can't do via the prototype, sincelike our StudentGuide is supposedfunction earlier assigning to derive from Parentthis.a. In technical terms: It's calling, Parent.call(this); calls the Parent function and, ensuring thatthis within the call to Parent, is the value passed into thiscall refers to(which is, in this case, the same object that this refersof the call to in Student (so that if Parent puts anything on it — e.g., it ends up on the rightnew object). If you're familiar with class-based languages, this is like doing super(); (that's Java, but you get the idea) in a derived constructor: It gives the base constructor a chance to initialize the object.
...because we shouldn't call Parent when creating Student's prototype property; we'llproperty, because that's for when Parent is setting up a specific instance. We'll do that within Student. (Using a specific object as a prototype is totally fine, but typically not what you want to do when you're using constructor functions to set things up.)
If you're interested in inheritance in JavaScript, I've written a helper script called Lineage you might want to look at, and in particular even if you don't use Lineage, this discussion on its wiki page may be useful for understanding inheritance hierarchies.
This isn't a very good implementation of inheritance, although parts of it are okay.
Here are those two lines explained:
Person.call(this);// <---- Confusion
When you call new Student(), within the call to Student, this is the new object created by the new operator. The line above is making sure that all the Parent things have been done to that new object, since Student is supposed to derive from Parent. In technical terms: It's calling the Parent function and ensuring that within the call to Parent, this refers to the same object that this refers to in Student (so that if Parent puts anything on it, it ends up on the right object). If you're familiar with class-based languages, this is like doing super(); (that's Java, but you get the idea) in a derived constructor.
...because we shouldn't call Parent when creating Student's prototype property; we'll do that within Student.
To explain it, first let's remember how constructor functions work in JavaScript:
function Guide(a) {
this.a = a;
}
Guide.prototype.q = "Life, the Universe, and Everything";
var g = new Guide(42);
console.log(g.q); // "Life, the Universe, and Everything"
console.log(g.a); // 42
When we do new Guide(42), the new operator creates a new object and assigns it a prototype using the Guide.prototype property. Then new calls Guide, passing in that new object as this. Guide uses this to add properties to the new object that aren't on its prototype. Then the new expression completes and its result is the new object that it created.
When we look at g.q, since the g object doesn't have its own property called q, the JavaScript engine looks at g's prototype, which (again) it got assigned when it was created. That prototype has a q property, and so the engine uses its value.
In contrast, when we look at g.a, the g object has its own property called a, and so the value is used directly.
With that foundation in place, let's look at Student and Parent:
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
When we call new Student(), within the call to Student, this is (again) the new object created by the new operator, which has Student.prototype as its underlying prototype. But the Parent function hasn't had a chance to do anything with this new object. So what that line does is give Parent a chance to do whatever it needs to do to new objects that it can't do via the prototype, like our Guide function earlier assigning to this.a. In technical terms, Parent.call(this); calls the Parent function, ensuring thatthis within the call to Parent is the value passed into call (which is, in this case, the this of the call to Student — e.g., the new object). If you're familiar with class-based languages, this is like doing super(); (that's Java, but you get the idea) in a derived constructor: It gives the base constructor a chance to initialize the object.
...because we shouldn't call Parent when creating Student's prototype property, because that's for when Parent is setting up a specific instance. We'll do that within Student. (Using a specific object as a prototype is totally fine, but typically not what you want to do when you're using constructor functions to set things up.)
If you're interested in inheritance in JavaScript, I've written a helper script called Lineage you might want to look at, and in particular even if you don't use Lineage, this discussion on its wiki page may be useful for understanding inheritance hierarchies.
This isn't a very good implementation of inheritance, although parts of it are okay.
Here are those two lines explained:
Person.call(this);// <---- Confusion
When you call new Student(), within the call to Student, this is the new object created by the new operator. The line above is making sure that all the Parent things have been done to that new object, since Student is supposed to derive from Parent. In technical terms: It's calling the Parent function and ensuring that within the call to Parent, this refers to the same object that this refers to in Student (so that if Parent puts anything on it, it ends up on the right object). If you're familiar with class-based languages, this is like doing super(); (that's Java, but you get the idea) in a derived constructor.
// inherit Person
Student.prototype = new Person(); //<---- Confusion
Since Student is supposed to inherit from Person, what that code is doing is creating the prototype that will be assigned to objects created via new Student. The object it's creating is a Person object.
The more correct way to create Student's prototype property looks like this:
function derive(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
}
derive(Student, Parent);
...because we shouldn't call Parent when creating Student's prototype property; we'll do that within Student.