Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call parent function which is being overridden by child during constructor chain in JavaScript(ES6) [duplicate]

I've encounter a problem below with JavaScript(ES6)

class A{   constructor(){     this.foo();   }   foo(){     console.log("foo in A is called");   } }  class B extends A{   constructor(){     super();     this.foo();   }   foo(){     console.log("foo in B is called");   } } 

What I expect is

foo in A is called foo in B is called 

But actually it is

foo in B is called foo in B is called 

I know I can resolve this by simply adding super.foo() in class B's foo function

class B extends A{   constructor(){     super();     this.foo();   }   foo(){     super.foo() // add this line     console.log("foo in B is called");   } } 

But imagine a scenario similar to this:

Child has to override parent's function in order to do some extra works and prevent access from outer being able to access to the original one.

class B extends A{   constructor(){     super();     this.initBar();   }   foo(){     super.foo();     this.bar.run(); //undefined     console.log("foo in B is called");   }   initBar(){     this.bar.run = function(){       console.log("bar is running");     };   } } 

It seems that this still points to child B while constructing in parent A. That's why I can't reach parent A's foo.

How do I make this to call parent version function which is being overridden by child during constructor chain?

Or is there any better solution when it comes to scenario like this?

Edit

So, after reading answers, the main question becomes --

Is it discouraged to put initialize helpers or setter functions in constructor in JavaScript since children have a chance to override them?

To clarify the situation more clearly: (sorry for my previous bad example :( )

class A{   constructor(name){     this.setName(name);   }   setName(name){     this._name = name;   } }  class B extends A{   constructor(name){     super(name);     this._div = document.createElementById("div");   }   setName(name){     super.setName(name);     this._div.appendChild(document.createTextNode(name));   } }  new B("foo") 

this._div will be undefined.

Is this a bad idea since child will be able to override the function?

class A{   constructor(name){     this.setName(name); // Is it bad?   }   ... } 

So I shouldn't use initialize helpers or setter functions in constructor like in Java, C++...?

Must I manually call things like this new A().init() to help me initialize things?

like image 801
andrew Avatar asked Sep 16 '15 17:09

andrew


People also ask

Which keyword is used to call the base parent class functions from the child functions in JavaScript?

constructor = sub; } // parent class function ParentObject(name) { this.name = name; } // parent's methods ParentObject. prototype = { myMethod: function(arg) { this.name = arg; } } // child function ChildObject(name) { // call the parent's constructor ParentObject. call(this, name); this.

How to implement inheritance in JavaScript?

JavaScript super() keyword log(`Hello ${this.name}`); } } // inheriting parent class class Student extends Person { constructor(name) { console. log("Creating student class"); // call the super class constructor and pass in the name parameter super(name); } } let student1 = new Student('Jack'); student1. greet();

Which method refers to the parent class in JavaScript?

Direct calling method: Since a derived class has access to all characteristics of its base class, using child class's object to refer to parent class's function makes perfect sense.

Which JavaScript feature Do we need to use when we want to call attributes methods and values of parent class into a child class?

The super keyword is used to call the constructor of its parent class to access the parent's properties and methods.


1 Answers

You seem to be operating under a misconception that there are two objects A and B when you are in the constructor of the derived class B. This is not the case at all. There is one and only one object. Both A and B contribute properties and methods to that one object. The value of this will be the same in the constructor for B as it is in the constructor for A during the creation of an object of class B.

The ES6 class syntax is just sugar over the ES5 method of using prototypes for object types and, in fact, the prototype is still used under the covers. As such, when you define a method foo in a derived class like you do in class B, it is still assigning to the prototype and that assignment overrides any method of the same name that might already exist on the prototype that came from the parent definition. This is why this.foo() refers to the class B version of foo. If you want to reach the class A version of foo, then you will have manually specify that using super as you appear to already know.

As for your specific questions:

It seems that this still points to child B while constructing in parent A. That's why I can't reach parent A's foo.

child B and parent A are not separate objects. There is one object that both parent A and child B reference. parent A and child B methods or constructors will see the exact same value of this.

How do I make this to call parent version function which is being overridden by child during constructor chain?

You use super to reference parent methods directly as you appear to already know.

Or is there any better solution when it comes to scenario like this?

super is the solution.


FYI, this is a pretty good discussion on ES6 classes including how super works: Classes in ECMAScript 6 (final semantics). Section 4.4 seems particularly relevant to your question/understanding.

like image 155
jfriend00 Avatar answered Oct 08 '22 20:10

jfriend00