allez l'OM
allez l'OM

Reputation: 577

javascript hasOwnProperty prototype and inheritance

I've checked questions: javascript what is property in hasOwnProperty? and javascript hasOwnProperty and prototype but couldn't find the answer to my problem. Here is my code: But some answers are puzzling me (NOT as expected).

function School(schoolName) {
  this.schoolName = schoolName;
}
School.prototype.printSchoolName = function() {
  console.log(this.schoolName);
}

function Student(studentName, schoolName) {
  this.studentName = studentName;
  this.schoolName = schoolName; // alternative : School.call(this, schoolName);
}
Student.prototype = new School(); // force l'héritage des propriétés de School
Student.prototype.printStudentName = function() {
  console.log(this.studentName);
}
var s = new Student("Victor", "IUT");
s.printStudentName(); // works fine
s.printSchoolName(); // works fine
console.log(Student.prototype.hasOwnProperty("printStudentName")); // works as expected: true
console.log(Student.prototype.hasOwnProperty("printSchoolName")); // works as expected: false
console.log(Student.prototype.hasOwnProperty("studentName")); //  NOT as expected: false
console.log(School.prototype.hasOwnProperty("schoolName")); //  NOT as expected: false
console.log(Object.getOwnPropertyNames(new School())); // schoolName
console.log(Object.getOwnPropertyNames(new Student())); // studentName, schoolName

The last 2 alerts don't mention the methods, though these methods have been detected by hasOwnProperty. Puzzling. Thank you.

Upvotes: 1

Views: 586

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074505

The first thing to note is that using new School to set up Student.prototype is an anti-pattern. It's an anti-pattern you see a lot, but it's an anti-pattern. (It's also bizarre: Student has an "is-a" relationship with School?! Normally there'd be a "has-a" relationship [not inheritance], but not an "is-a"...) We'll come back to it.

Answering:

console.log(Student.prototype.hasOwnProperty("studentName"));
//  NOT as expected: false

Nothing ever sets a studentName property on Student.prototype, so it's no surprise that it doesn't have the property. The Student function will set one on the instance when you call it, but Student.prototype isn't an instance created by new Student, so it's never had one set on it.

Moving on to:

console.log(School.prototype.hasOwnProperty("schoolName"));
//  NOT as expected: false

Same explanation.

Moving on to:

console.log(Object.getOwnPropertyNames(new School()));
// schoolName
console.log(Object.getOwnPropertyNames(new Student()));
// studentName, schoolName

The reason you don't see the prototype methods there is because getOwnPropertyNames shows only the names of properties directly set on the object you call it on (the new School object and the new Student object). The methods aren't directly set on those, they're set on the prototype of those objects. So they're not listed.


Re the anti-pattern: In ES5 and earlier syntax, the correct way to set up prototypical inheritance with constructor functions is via Object.create, not calling the constructor. Also, after replacing the object on a function's prototype property, it's useful to set its constructor property back to what it should be:

Student.prototype = Object.create(School.prototype);
Student.prototype.constructor = Student;

Of course, in ES2015 (aka "ES6") and later, you can use class notation (transpiling if necessary for older browsers), which handles doing it correctly for you.

Upvotes: 3

Joel Blum
Joel Blum

Reputation: 7878

maybe part of the confusion is hasOwnProperty doesn't work as you think for constructor function. But works as you'd expect for the instance:

a = new Student()
a.hasOwnProperty("studentName") //true 

Upvotes: 0

Related Questions