2

Purpose: inherit only the object keys, not the ones inherited

Two constructor: Person and Teacher. Teacher is inheriting properties using prototypal inheritance.

Height and weight are the two keys inherited from person to teacher.

To my understanding for ... in loops through all the keys in the object as well as keys inherited. Therefore hasOwnProperty is used to filter the properties only available within the Teacher object. However the code outputs all the properties including height and weight which it should not.

/* eslint-disable no-console */

function Person(first, last, age, gender, interests, weight, height) {
  this.name = {
    first,
    last,
  };
  this.age = age;
  this.gender = gender;
  this.interests = interests;
  this.weight = weight;
  this.height = height;
}

Person.prototype.greeting = () => {
  console.log(`Hi! I'm ${this.name.first}.`);
};

function Teacher(first, last, age, gender, interests, subject) {
  Person.call(this, first, last, age, gender, interests);

  this.subject = subject;
}

Teacher.prototype.greeting = () => {
  let prefix;

  if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
    prefix = 'Mr.';
  } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
    prefix = 'Mrs.';
  } else {
    prefix = 'Mx.';
  }

  console.log(`Hello. My name is ${prefix} ${this.name.last}, and I teach ${this.subject}.`);
};

Teacher.prototype = Object.create(Person.prototype);

Object.defineProperty(Teacher.prototype, 'constructor', {
  value: Teacher,
  enumerable: false, // so that it does not appear in 'for in' loop
  writable: true,
});

const teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');

for(var key in teacher1){
  if(teacher1.hasOwnProperty(key)){
    console.log(key);
  }
}

// Output: name, age, gender, interests, weight, height, subject
// weight and height should not be here
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639

1 Answers1

4

The name, age, etc., properties on teacher1 are own properties. They are not inherited from teacher1's prototype (Teacher.prototype) or its prototype (Person.prototype). Although it's Person that assigns them, they're still own properties. this in the call to Person from Teacher is the object that will be assigned to teacher1, so

this.age = age;

...makes age an own property of teacher1.

Once the property has been created on the object, there's no way to know what function (if any) created it.


There are a couple of other problems with your code:

  1. You're assigning an arrow function to Teacher.prototype.greeting. Don't use arrow functions for methods that will be inherited, this won't be set correctly. A couple of related questions whose answers may be useful:

  2. You're assigning to Teacher.prototype.greeting, then later replacing Teacher.prototype entirely (Teacher.prototype = Object.create(Person.prototype);). So you won't have the greeting method on it.

  3. If you replace the object on Teacher.prototype the way you are, it's important to make sure its constructor property is correct:

    Teacher.prototype = Object.create(Person.prototype);
    Teacher.prototype.constructor = Teacher; // <===
    

But: Since you're using ES2015+ features anyway (arrow functions, template literals, ...), you can make this all much simpler by using class syntax.

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • 1
    Thank You for replying. If I manually write the teacher constructor like (( this.name = { first, last, }; this.age = age; this.gender = gender; this.interests = interests; this.subject = subject; } )) then the output seems to be correct and doesn;t include weight and height. Why the person.call is creating the weight and height properties when the Teacher constructor never asks for it? – Mehul Bechra Nov 27 '18 at 17:30
  • 1
    @MehulBechra - Because the code in `Person` that creates those properties isn't in any way conditional. You just have `this.weight = weight;` (and the same for `height`). In JavaScript, if you don't pass an argument for a parameter, the function sees the parameter's value as `undefined` (the actual value `undefined`). `this.weight = undefined;` creates a property called `weight` with the value `undefined` (which isn't the same as not having the property at all). – T.J. Crowder Nov 27 '18 at 17:34
  • 2
    Cheers!. Got it. – Mehul Bechra Nov 27 '18 at 17:38