Es6 Calling Super() Doesn't Properly Initialize Parent Class
Solution 1:
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:
newcreates a new object whose[[Prototype]]isChild.prototype.Child.prototype's[[Prototype]]isParent.prototype.newcallsChild.ChildcallsParent.this._init()looks up the_initproperty on the object. Since the object doesn't have its own_initproperty, the JavaScript engine looks to its[[Prototype]].Child.prototypedoes have an_initproperty, 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. 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:
classParent {
  constructor() {
    console.log('P constructor');
    this.parentProp = 'parent';
  }
}
classChildextendsParent {
  constructor() {
    console.log('C constructor');
    super();
    this.childProp = 'child';
  }
  test() {
    console.log(this.childProp + ' ' + this.parentProp);
  }
}
let child = newChild();
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:
letParent = (function() {
  classParent {
    constructor() {
      console.log('P constructor');
      initParent.call(this);
    }
  }
  functioninitParent() {
    console.log("initParent");
    this.parentProp = 'parent';
  }
  returnParent;
})();
letChild = (function() {
  classChildextendsParent {
    constructor() {
      console.log('C constructor');
      super();
      initChild.call(this);
    }
    test() {
      console.log(this.childProp + ' ' + this.parentProp);
    }
  }
  functioninitChild() {
    console.log("initChild");
    this.childProp = 'child';
  }
  returnChild;
})();
let child = newChild();
child.test();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.
Solution 2:
The best solution is not to use an init method at all. A constructor should not call overwritable methods:
classParent {
  constructor() {
    console.log('P constructor()');
    this.parentProp = 'parent';
  }
}
classChildextendsParent {
  constructor() {
    console.log('C constructor');
    super();
    this.childProp = 'child';
  }
  test() {
    console.log(this.childProp + ' ' + this.parentProp);
  }
}
let child = newChild();
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:
classChildextendsParent {
  constructor() {
    console.log('C constructor');
    super();
  }
  _init() {
    super._init();
    console.log('C _init()');
    this.childProp = 'child';
  }
  …
Solution 3:
Basically here in our case super() is equals to Parent.call(this), Where this would points to Child. So Child.prototype._init will be called twice and that property parentProp will not be created.
And this is the reason why, you are seeing the following console outputs.
C constructor()
Pconstructor()
C _init() //printed from Child.prototype._init
C _init() //printed from Child.prototype._init
child undefined
Post a Comment for "Es6 Calling Super() Doesn't Properly Initialize Parent Class"