I have the following code structure, I try to initialize parent class by calling super(), but when i call this._init() it calls the one of the child. any help how can I fix this?
class Parent {
    constructor() {
    console.log('P constructor()');
    this._init();
  }
  _init() {
    console.log('P _init()');
    this.parentProp = 'parent';
  }
}
class Child extends Parent {
    constructor() {
    console.log('C constructor');
    super();
    this._init();
  }
  _init() {
      console.log('C _init()');
    this.childProp = 'child';
  }
  test() {
    console.log(this.childProp + ' ' + this.parentProp);
  }
}
let child = new Child();
child.test();
Here's the output of the above code:
C constructor()
P constructor()
C _init()
C _init()
child undefined
Child#_init is getting called because that's what the _init property on the object refers to when this._init() (in Parent) is called. What happens (leaving out some details) is:
new creates a new object whose [[Prototype]] is Child.prototype. Child.prototype's [[Prototype]] is Parent.prototype.new calls Child.Child calls Parent.this._init() looks up the _init property on the object. Since the object doesn't have its own _init property, the JavaScript engine looks to its [[Prototype]]. Child.prototype does have an _init property, so the engine uses that one.As for solving it: JavaScript classes have only one constructor, so there's no real purpose to having a separate _init function.1 That's what constructors are for. Despite their name, they don't construct objects, they initialize them. So just put _init's code in the constructor itself:
class Parent {
  constructor() {
    console.log('P constructor');
    this.parentProp = 'parent';
  }
}
class Child extends Parent {
  constructor() {
    console.log('C constructor');
    super();
    this.childProp = 'child';
  }
  test() {
    console.log(this.childProp + ' ' + this.parentProp);
  }
}
let child = new Child();
child.test();Alternately, just remove the this._init() call from Child entirely and have Child#_init call super._init(). I know you've said in a comment you think that's poor practice (it isn't, it's standard practice), but if you want to break out _init to separate functions, that's what you do. But doing so violates the principal, well-established cross-language, that calling overrideable methods from a constructor (Parent calling this._init()) is a Bad Idea™. :-)
If you absolutely insist on separating the code out into a function, and don't want to use super._init() in Child#_init, it'll need to be separate from the class:
let Parent = (function() {
  class Parent {
    constructor() {
      console.log('P constructor');
      initParent.call(this);
    }
  }
  function initParent() {
    console.log("initParent");
    this.parentProp = 'parent';
  }
  return Parent;
})();
let Child = (function() {
  class Child extends Parent {
    constructor() {
      console.log('C constructor');
      super();
      initChild.call(this);
    }
    test() {
      console.log(this.childProp + ' ' + this.parentProp);
    }
  }
  function initChild() {
    console.log("initChild");
    this.childProp = 'child';
  }
  return Child;
})();
let child = new Child();
child.test();1 I could see using a method in a language with overloaded constructors — although even there I advocate having them call each other rather than a utility method — but not in JavaScript.
The best solution is not to use an init method at all. A constructor should not call overwritable methods:
class Parent {
  constructor() {
    console.log('P constructor()');
    this.parentProp = 'parent';
  }
}
class Child extends Parent {
  constructor() {
    console.log('C constructor');
    super();
    this.childProp = 'child';
  }
  test() {
    console.log(this.childProp + ' ' + this.parentProp);
  }
}
let child = new Child();
child.test();
Alternatively, in your case it would have worked to call the super method in _init and not to call _init from the Child constructor:
class Child extends Parent {
  constructor() {
    console.log('C constructor');
    super();
  }
  _init() {
    super._init();
    console.log('C _init()');
    this.childProp = 'child';
  }
  …
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With