在JavaScript(ES6)的构造函数链中调用由子进程覆盖的父函数

时间:2015-09-16 17:28:15

标签: javascript class constructor this ecmascript-6

我在下面遇到了JavaScript(ES6)

的问题
class A{
  constructor(){
    this.foo();
  }
  foo(){
    console.log("foo in A is called");
  }
}

class B extends A{
  constructor(){
    super();
    this.foo();
  }
  foo(){
    console.log("foo in B is called");
  }
}

我期待的是

foo in A is called
foo in B is called

但实际上它是

foo in B is called
foo in B is called

我知道我可以通过简单地在B类的foo函数

中添加super.foo()来解决这个问题
class B extends A{
  constructor(){
    super();
    this.foo();
  }
  foo(){
    super.foo() // add this line
    console.log("foo in B is called");
  }
}

但想象一下类似的情况:

Child必须覆盖父级的功能才能执行一些额外的工作,并阻止外部访问能够访问原始功能。

class B extends A{
  constructor(){
    super();
    this.initBar();
  }
  foo(){
    super.foo();
    this.bar.run(); //undefined
    console.log("foo in B is called");
  }
  initBar(){
    this.bar.run = function(){
      console.log("bar is running");
    };
  }
}

在父this中构建时,B似乎仍指向子A。这就是为什么我无法联系到父A的{​​{1}}。

如何让foo调用构造函数链中被子进程覆盖的父版本函数?

或者在这样的场景中有没有更好的解决方案?

修改

因此,在阅读答案后,主要问题变为 -

是否不建议在JavaScript中将thisinitialize helpers置于构造函数中,因为孩子有机会覆盖它们?

更清楚地澄清情况:(对不起我之前的坏例子:()

setter functions

class A{ constructor(name){ this.setName(name); } setName(name){ this._name = name; } } class B extends A{ constructor(name){ super(name); this._div = document.createElementById("div"); } setName(name){ super.setName(name); this._div.appendChild(document.createTextNode(name)); } } new B("foo") 将为this._div

这是一个坏主意,因为孩子可以覆盖这个功能吗?

undefined

所以我不应该像Java,C ++那样在构造函数中使用class A{ constructor(name){ this.setName(name); // Is it bad? } ... } initialize helpers

我是否必须手动调用此setter functions之类的内容来帮助我初始化内容?

1 个答案:

答案 0 :(得分:18)

当您处于派生类A的构造函数中时,您似乎在误解下有两个对象BB。事实并非如此。只有一个对象。 AB都为这一个对象提供了属性和方法。 this的构造函数中的B的值与在创建B类对象期间A的构造函数中的值相同。

ES6类语法只是使用原型用于对象类型的ES5方法的糖,事实上,原型仍然在封面下使用。因此,当您在类B中定义派生类中的方法foo时,它仍然会分配给原型,并且该赋值将覆盖原型上可能已存在的任何同名方法。来自父定义。这就是this.foo()引用foo的B类版本的原因。如果您想要达到foo的A级版本,那么您将使用super手动指定该版本,因为您似乎已经知道了。

至于你的具体问题:

  

似乎这仍然指向孩子B在建造时   父母A.这就是为什么我无法联系父母A的原因。

子B和父A不是单独的对象。父A和子B都有一个对象引用。父A和子B方法或构造函数将看到完全相同的this值。

  

如何使其调用正在进行的父版本功能   在构造函数链中由子进行覆盖?

您可以使用super直接引用父方法,因为您似乎已经知道了。

  

或者在这样的场景中有没有更好的解决方案?

super是解决方案。

仅供参考,这是关于ES6课程的一个非常好的讨论,包括super的工作原理:Classes in ECMAScript 6 (final semantics)。第4.4节似乎与您的问题/理解特别相关。