6

I'm studying the concept of inheritance in Javascript, and the tutorial I'm looking at uses this code:

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = new Person();

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

My question is, why is it necessary to both call the parent constructor, Person.call(this), and set the Student prototype equal to a new Person object (i.e. Student.prototype = new Person();)?

Krizz
  • 11,362
  • 1
  • 30
  • 43
voltair
  • 615
  • 2
  • 7
  • 21

2 Answers2

5

There are two separate issues to deal with.

The first is to make sure new Student objects inherit from Person objects. That's why you do Student.prototype = new Person(). That makes the Student.prototype a Person so Student objects will inherit whatever that object inherits (from Person.prototype).

The second is to apply any behavior in the Person constructor to any new Student objects. That's why you do Person.call(this). This is technically not needed if the Person constructor doesn't have any code that modifies the new object, but it's still a good idea to do it just in case you add some code to Person later.


Side note, when setting up the inheritance, it's better to do:

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

...and shim Object.create if needed. This way you don't actually need to invoke the Person constructor in order to get a new object that inherits from Person.prototype. Again, sometimes not an issue, but sometimes there are side effects in the constructor that are undesired when setting up the inheritance.

  • I'm just curious... what is the reason for setting the prototype's constructor? `Student.prototype.constructor = Student;` – DigitalZebra Apr 05 '13 at 21:28
  • 2
    +1 For the fix removing `new Person()` which could be problematic in case where parent constructor have parameters. Also within the constructor, one could send arguments too. – Loïc Faure-Lacroix Apr 05 '13 at 21:28
  • 1
    @Polaris878: It's because the default `Student.prototype` object has a `.constructor` property that points to the `Student` function... but that object is being replaced, so if the `.constructor` property is desired, it needs to be manually added to the new object. –  Apr 05 '13 at 21:31
  • But aren't we effectively calling the constructor twice? What is the difference between Person.call(this) and new Person()? Why aren't changes to the object within the object's defining function reflected in the object's prototype? – voltair Apr 06 '13 at 04:15
  • @voltair: `new Person` is for creating a new object. That new object within the `Person` function is referenced by `this`. When we do `Person.call(this)`, we're taking the current `this`, which is the new `Student` object, and manually setting it as the `this` value of the `Person` function. Put it this way... in JavaScript, inheritance has almost nothing to do with constructor functions. Constructors are not automatically invoked when one object inherits from another. The constructor functions are just a weird, confusing way of setting up the prototypal relationship between two objects. –  Apr 06 '13 at 14:18
  • @amnotiam Please see my answer to see if you agree. – voltair Apr 06 '13 at 19:02
0

After doing some testing, to my understanding, the prototype of an object and the property declarations made within its defining function are separate. However, when one constructs a new object, the constructor will pull properties from both the defining function and the prototype of the object being created.

For example,

function Person()
{

    this.name = "james";
    this.age = "shfifty-five";


}

console.log(Person.prototype.name); // prints "undefined", showing how declaring function Person() and Person.prototype are separate.

Person.prototype.gender = "male";

var human = new Person();

console.log(human.name); // prints "james", showing how the object took properties from declaring function Person().
console.log(human.gender); // prints "male", showing how the object took properties from object prototype Person.prototype.


function Student()
{

    this.gpa = 4.00;


}



Student.prototype = new Person();

Student.prototype.constructor = Student;


var myStudent = new Student();

console.log(myStudent.name); // prints "james"
console.log(myStudent.gender); // prints "male"
/*from above two lines, inheritance holds even though 1) Person() defining function was not called inside Student() defining function
and 2) Person() defining function declares properties of Person object.*/
console.log(myStudent.gpa); // prints "4"

As you can see, in this case the defining function Person does alter the properties of its object. But it is still not necessary to call the Person function within the constructor of Student, because the new Person() constructor will pull properties from both Person.prototype and the function Person() defining function.

voltair
  • 615
  • 2
  • 7
  • 21
  • 1
    It depends... Every new `Student` object will inherit properties from the `Student.prototype` object. In your example, when you do `Student.prototype = new Person()`, there are some properties being added to the `Person` object being assigned, so naturally those will be inherited. But what if the values being assigned in the `Person` constructor are not static? If you don't invoke `Person` on the new `Student` objects, they'll always be referencing the same property values set on the prototype object. If you *did* want static values to be inherited, you should put them on `Person.prototype`. –  Apr 06 '13 at 19:11