ES6调用super()没有正确初始化父类 [英] ES6 calling super() doesn't properly initialize parent class

查看:409
本文介绍了ES6调用super()没有正确初始化父类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码结构,我尝试通过调用super()来初始化父类,但是当我调用this._init()时,它调用该子对象。任何帮助如何解决这个问题?

  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();

以上代码的输出如下:

  C构造函数()
P构造函数()
C _init()
C _init()
child undefined


解决方案

Child#_init 正在调用,因为这是$ _init 属性对象是指当$ code> this._init()(在code> Parent )被调用。发生什么(省略一些细节)是:


  1. 创建一个新对象其 [[Prototype]] Child.prototype Child.prototype [[Prototype]] Parent.prototype

  2. new call Child

  3. Child call Parent

  4. this._init()查找对象上的 _init 属性。由于该对象没有自己的 _init 属性,因此JavaScript引擎将查找其 [[Prototype]] Child.prototype 具有 _init 属性,因此引擎使用该属性。 / li>

至于解决它:JavaScript类只有一个构造函数,所以没有真正的目的,要有一个单独的 _init function。 1 这是什么构造函数。尽管他们的名字,他们不构造对象,他们初始化他们。所以只需在构造函数本身中放入 _init 的代码:



  class Parent {constructor(){console.log('P constructor'); this.parentProp ='parent'; }} class Child extends Parent {constructor(){console.log('C constructor');超(); this.childProp ='child'; } test(){console.log(this.childProp +''+ this.parentProp); }} let child = new Child(); child.test();  



另外,只需从 Child 中删除​​ this._init()调用,并且 Child#_init call super._init()。我知道你在一个评论中说过,你认为这是不好的做法(这不是标准做法),但是如果你想打破 _init 来分离功能,这就是你所做的但是这样做违反了主要的,完善的跨语言,从构造函数( Parent 调用 this._init())是Bad Idea™。 : - )



如果您绝对坚持将代码分离成一个函数,并且不想使用 super._init() Child#_init 中,需要与课程分开:



div class =snippetdata-lang =jsdata-hide =falsedata-console =truedata-babel =false>

 






1 我可以看到使用一种具有重载构造函数的语言的方法 —虽然即使在那里,我主张让他们打电话给对方,而不是一个实用方法 —但不在JavaScript中。


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:

  1. new creates a new object whose [[Prototype]] is Child.prototype. Child.prototype's [[Prototype]] is Parent.prototype.
  2. new calls Child.
  3. Child calls Parent.
  4. 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.

这篇关于ES6调用super()没有正确初始化父类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆