ES6调用super()没有正确初始化父类

时间:2016-09-16 09:14:03

标签: javascript inheritance ecmascript-6 babeljs

我有以下代码结构,我尝试通过调用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 constructor()
P constructor()
C _init()
C _init()
child undefined

3 个答案:

答案 0 :(得分:3)

Child#_init被调用,因为当调用_init(在this._init()中)时,对象的Parent属性就是这样。会发生什么(遗漏一些细节)是:

  1. new创建一个[[Prototype]]Child.prototype的新对象。 Child.prototype的{​​{1}}是[[Prototype]]
  2. Parent.prototype来电new
  3. Child来电Child
  4. Parent在对象上查找this._init()属性。由于该对象没有自己的_init属性,因此JavaScript引擎会查找其_init[[Prototype]] 具有Child.prototype属性,因此引擎会使用该属性。
  5. 至于解决它:JavaScript类只有一个构造函数,所以没有真正的目的来拥有一个单独的_init函数。 1 这就是构造函数的用途。尽管他们的名字,他们不构造对象,他们初始化他们。所以只需将_init的代码放在构造函数本身中:

    _init

    或者,只需完全从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();移除this._init()来电,然后Child拨打Child#_init。我知道你在评论中说过你认为这是不好的做法(不是,这是标准做法),但是如果你想突破super._init()来分离职能,那就是你所做的。但这样做违反了主要的,完善的跨语言,从构造函数(_init调用Parent)调用可重写方法是一个坏主意™。 : - )

    如果你绝对坚持将代码分离到一个函数中,并且不想在this._init()中使用super._init(),那么它将需要与该类分开:

    Child#_init

    1 我可以看到在一个带有重载构造函数的语言中使用一个方法 - 尽管在那里我主张让它们相互调用而不是实用方法 - 但不是在JavaScript中。

答案 1 :(得分:1)

最好的解决方案是根本不使用true方法。构造函数不应该调用可覆盖的方法:

init

或者,在您的情况下,它可以在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(); 中调用super方法,而不是从Child构造函数调用_init

_init

答案 2 :(得分:0)

基本上我们的情况import {Link} from "react-router"; interface LinkProps { to?: HistoryModule.LocationDescriptorObject; onClick?: (event: React.FormEvent) => void; children?: React.ReactNode; } const LinkPresenter: React.SFC = (props: LinkProps): JSX.Element => <Link className="link" to={props.to} onClick={props.onClick} > {props.children} </Link>; // Alternative syntax const LinkPresenter: React.StatelessComponent = (props: LinkProps): JSX.Element => ... LinkPresenter.defaultProps = { // now we can use defaultProps to: { pathname: `/homepage`, query: { default: 'someDefault' } }, onClick: () => {}, children: <span>Hello world</span>, }; 等于super(),其中Parent.call(this)指向this。因此,Child将被调用两次,并且不会创建属性Child.prototype._init

这就是为什么你会看到以下控制台输出。

parentProp