Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS Inheritance: calling the parent's function from within the child's function

There must be something I don't understand about the JS object model.

From these resources:

  • Prototypes
  • Basic OOP in JS- Inheritance
  • Object.create()

I have gathered what I think, or thought, was an accurate mental representation of the object model. Here it is:


All objects have a property, which the docs refer to as [[Prototype]]. [[Prototype]] can be thought of as a reference to the object's parent. More accurately:

The reference to the [parent's] prototype object is copied to the internal [[Prototype]] property of the new instance. (source 1)

You can get access to the [[Prototype]] property of the child with Object.getPrototypeOf(child) The value returned here will be a reference to the parent's prototype (not its internal [[Prototype]] property, but its actual prototype)

obj.prototype is different from the object's internal [[Prototype]] property. It acts like the blueprints used to make instances of this exact object, while its [[Prototype]] property points to the blueprints used to make instances of its parent.

  • Parent.prototype === Object.getPrototypeOf(child); //true

To elaborate:

  • If you add a function to child.prototype the function will be available to child and any of it's children.

  • If you add a function to parent.prototype, which is equivalent to adding a function to Object.getPrototypeOf(child), then the function will be available to parent and all of it's children, which includes child and all of its siblings.

You can use Object.create() to create a new object with whatever [[Protoype]] property you want. So you can use it as a way to implement inheritance. See source 2 for an example.


With this in mind, I wanted to get a working example of my own going. My plan was to create a parent 'class' and then make a child 'class' that inherited from it.

I wanted the child class to implement a method, which overloaded a method from the parent. The caveat is that I want the child's version of the method to call the parent's version of the method and then do some extra stuff.

Here is what I came up with, see below for the issues associated with it:

var Parent = function() {};

Parent.prototype.myF = function() {
  console.log('derp');
};


function Child() {
  Parent.call(this);
};

//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);

//need to explicitly set the constructor
Child.prototype.constructor = Child;

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};

childInstance = new Child();
childInstance.myF();

It appears to be the case that when I attempt to overload Parent.myF(), while I am overloading it, I am actually modifying the original function at the same time. This appears to be the case because the logged results are:

'derp'
'did I derp??'
'did I derp??'

presumably the first occurance of 'did I derp??' is coming from a modified version of the parent's function, which I don't mean to do, then the second version is coming from the child's function.

Can anyone elaborate on why this is happening?

like image 314
Luke Avatar asked May 22 '15 16:05

Luke


People also ask

How do you call a parent function from a child function?

To call a parent's function from a child component, pass the function reference to the child component as a prop. Then you can call that parent's function from the child component like props. parentMethodName(). In the example code, we create a parent component named Parent.

How do you call a parent function from a child in node JS?

prototype = { myMethod: function(arg) { this.name = arg; } } // child function ChildObject(name) { // call the parent's constructor ParentObject. call(this, name); this. myMethod = function(arg) { // HOW DO I CALL THE PARENT METHOD HERE? // do stuff } } // setup the prototype chain extend(ParentObject, ChildObject);

Can a child class call a parent method?

We can use super. method() in a Child method to call Parent method.

Can a parent class inherit from a child class?

Inheritance concept is to inherit properties from one class to another but not vice versa. But since parent class reference variable points to sub class objects. So it is possible to access child class properties by parent class object if only the down casting is allowed or possible....


2 Answers

Great question, it took a bit of testing and researching to find it out.

Identifying the strange behaviour

I changed your code a little bit to find out which function is called when:

var Parent = function() {};

Parent.prototype.myF = function() {
  console.log('derp');
};


function Child() {
  Parent.call(this);
  this.name = 'Test'; // this is a new test property
};

//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);

//need to explicitly set the constructor
Child.prototype.constructor = Child;

Child.prototype.myF = function() {
  console.log(this); // here I want to find out the context, because you use it in the next line
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};

childInstance = new Child();
childInstance.myF();

You can check out the JSFiddle and try it for yourself: http://jsfiddle.net/Lpxq78bs/

The crucial line in your code is this:

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF(); // this one
  console.log("did I derp??");
};

After doing a console.log(this); to find out what this refers to, I saw that it changes between the first and the second output of did I derp??.

I got the following output:

Object { name: "Test" }
Object { constructor: Child(), myF: window.onload/Child.prototype.myF() }
"derp"
"did I derp??"
"did I derp??"

Interpreting the Output

Since I added a 'name' property to the Child constructor, it would only be around if I am looking at an instance of Child, not at its .prototype.

So the first line of the Output means that the current this context is indeed the childInstance. But the second one is neither the childInstance, nor the Parent.prototype:

  1. Call (myF of childInstance): this refers to the childInstance. Object.getPrototypeOf(this).myF(); then looks for the [[Prototype]] of the childInstance, which is the Child.prototype, not the Parent.prototype. Output: 'did I derp??'

  2. Call (myF of Child.prototype): this refers to the Child.prototype, which is the childInstances [[Prototype]] Property. So the second call of Object.getPrototypeOf(this).myF(); finally returns the Parent.prototype (sort of). Output: 'did I derp??'

  3. Call (myF of Parent.prototype instance created by Object.create): Finally, the myF on the parent is called. Output: 'derp'

Since your console.log("did I derp??") comes after the myF function call, the output is in reverse order. The following graphic illustrates how the code is traversed:

enter image description here

So your assumption about what Object.getPrototypeOf(this).myF(); refers to, was wrong.

Solution in ES5

By @LukeP: https://jsfiddle.net/Lpxq78bs/28/

Alternative Solution in ES6

To avoid this confusion, and since you are working with a classical inheritance pattern, you could have a look at ES6 Classes. The following would be a rough example of what you are trying to do:

class Parent {
    constructor() {
      
    }
    
    myF() {
        console.log('derp');
    }
}

class Child extends Parent {
    constructor() {
        super();
    }

    myF() {
        super.myF();
        console.log("did I derp??");
    }
}

var childInstance = new Child();
childInstance.myF();

I hope this helps in understanding what happens.

like image 151
nils Avatar answered Sep 18 '22 20:09

nils


Your code is working as expected , the output you are getting is because of Object.getPrototypeOf and can be explained by

Step 1 : When you cal childInstance.myF(); then it goes to below code where this refers to childInstance itself

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};

then Object.getPrototypeOf returns childInstance.[[Prototype]] which is Child.prototype and again call myF method(leaving second line to printed later after the execution of the method) but next time this will reference to childInstance.[[Prototype]].

Step 2 : In this call this points to childInstance.[[Prototype]]( or Child.prototype object itself)

Child.prototype.myF = function() {
  Object.getPrototypeOf(this).myF();
  console.log("did I derp??");
};

Now Object.getPrototypeOf returns childInstance.[[Prototype]].[[Prototype]]( which is Child.prototype.[[Prototype]]) which is Parent.prototype and again call myF method but this time myF method will print derp because myF method of Parent.prototype is being called. After that, second line will print did i derp.

Step 3 : Then the function comes back to step 1 to execute second line which again prints did i derp

like image 40
bugwheels94 Avatar answered Sep 19 '22 20:09

bugwheels94