父类构造函数在所有子类构造函数完成之前调用重写函数

7

ECMAScript 6 (Harmony)引入了,可以继承自另一个类。假设我有一个游戏和一些基本的类来描述机器人行为的基本事物。我简化了我的真实架构,但是假设我需要运行渲染(render)和其他一些例行程序,并将这些调用放在基本的Bot类中。

class Bot{
  constructor(){
    render();
  }
  render(){}
}

每个机器人都会覆盖其render函数,并且可以在构造函数中设置一些参数:
class DevilBot extends Bot{
  constructor(){
    super();
    this.color = 0xB4D333;
  }
  render(){
    createSomeMesh(this.color);
  }
}

问题在于在调用 super() 之前,this 并不存在。但是 super (父类构造函数)将调用被覆盖的 render 函数,该函数需要在子类构造函数中定义的 color 变量。我可以假设在父类构造函数中,子对象会实现一些 init 函数 with 所有需要的设置并调用它:
class Bot{
  constructor(){
    if (this.init) this.init();
    render();
  }
  render(){}
}

class DevilBot extends Bot{
  init(){
    this.color = 0xB4D333;
  }
  render(){
    createSomeMesh(this.color);
  }
}

但是这种方法有多好,什么是解决这个问题的首选方式?

2
唯一的解决方案是不要在构造函数中调用可重写方法。在C#中这样做会给你一个警告 - Bryan Chen
解决方案可能就是不自动调用依赖于实例属性的其他函数(例如 render)。在调用您的 Bot 子类之后手动调用 this.render() 有什么问题吗?另外,要在类内部调用成员函数,您需要使用 this.render() 而不是 render() - Mulan
@naomik,我在构造函数中调用它的原因是在我的实际架构中,我有更复杂的代码例程,我不希望在每个子对象中重复。 - SET001
3
这似乎是设计不良。构造函数的目的是构建和初始化对象,而不是进行“渲染”(这是一种副作用)。 - Bergi
1
@Bergi,这看起来像是糟糕的设计,只是因为我在这个例子中使用了render来简化。正如我在之前的评论中所写的那样,在真实的架构中,我有更复杂的代码,我想要隐藏在父对象中。 - SET001
显示剩余5条评论
1个回答

5
以下代码可以实现您的需求,但目前只支持FF 41+和Chrome 47+(请参见https://kangax.github.io/compat-table/es6/)。
class Bot{
    constructor(){
        if (new.target === Bot)
            this.render();
    }
    render(){
        console.log('Bot rendered');
    }
}

class DevilBot extends Bot{
    constructor(){
        super();
        this.color = 0xB4D333;
        this.render();
    }
    render(){
        console.log('DevilBot rendered with', this.color);
    }
}

var bot = new Bot();       // Bot rendered
var dev = new DevilBot();  // DevilBot rendered with 11850547

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接