1

Hi guys I'm learning inheritance in JavaScript recently. I create a Child function and make it inherit the Human function. I create a child instance for Child then console.log(child).

I'm wondering why the outputs only have properties of Child, but no Human property.

I guess it's because the property descriptors, specifically the enumerable, but I can't figure it out. Can anyone help me?

const Child = function() {
  this.name = "child"
}

const Human = function() {
  this.move = "walking";
}

Child.prototype = new Human();
Child.prototype.constructor = Child;

const child = new Child();
console.log(child);

After running above code I only see {name: "child"}, though console.log(child.move) gives 'walking'.

Calvin Nunes
  • 6,376
  • 4
  • 20
  • 48
  • 1
    FYI: I see all the properties in Firefox. – user229044 Aug 26 '19 at 19:22
  • 1
    `move` and `constructor` are inherited properties. Maybe your console just doesn't show those? In what environment are you running this code? – Bergi Aug 26 '19 at 19:24
  • Every object in JS has a `__proto__` link that points to its prototype. If you console `child` in a browser (chrome, firefox), you will get `instance` properties listed followed by `__proto__` link. Once you expand that link, you will see those properties. Here is the image. Hope this helps! [![enter image description here][1]][1] [1]: https://i.stack.imgur.com/0po8s.png – Ravi Tiwari Aug 26 '19 at 19:29
  • thanks guys I have figured it out. – Miller Dong Aug 26 '19 at 21:02

1 Answers1

0

The short answer, is that move is not found on the Child instance, but on the prototype it inherits from Human.

Let's analyze your code.

const Child = function() {
  this.name = "child"
}

const Human = function() {
  this.move = "walking";
}

These are self explanatory, you make two constructor functions. They are unrelated (yet).

Child.prototype = new Human();
Child.prototype.constructor = Child;

This is the inheritance part. Child.prototype = new Human(); will create an instance of of Human, and assign it to Child.prototype, because the instance has a member move, that gets assigned to Child.prototype and you get what's essentially Child.prototype = { move: 'walking' } or Child.prototype.move = 'walking' (those aren't accurate, but close enough)

Then you assign Child itself as the prototype.constructor.


The reason you're seeing the weird behavior is that you expect move to be an instance member, but it's a prototype member instead. A more significant drawback of this effect is that altering child.move will alter it for all child instances at once, which is not what you'd expect from an instance member.

For this reason, it is not recommended to do inheritance by actually creating an instance, like you did, but using Object.create() instead, like so:

Child.prototype = Object.create(Human.prototype);
Child.prototype.constructor = Child;

Additionally, your Child function should be calling the parent constructor, to maintain the parent's logic and members. Like so:

const Child = function() {
  Human.call(this); // call to parent constructor
  this.name = "child";
}

Full code:

const Human = function() {
  this.move = "walking";
}
const Child = function() {
  Human.call(this);
  this.name = "child"
}
Child.prototype = Object.create(Human.prototype);
Child.prototype.constructor = Child;

const child = new Child();
console.log(child);

Once you understand how prototype chains work, remember that ES6 classes were created to handle these situations more gracefully and with more readable code:

class Human {
  constructor() {
    this.move = "walking";
  }
}

class Child extends Human {
  constructor() {
    super();
    this.name = "child";
  }
}
Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308