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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32615034/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 13:57:30  来源:igfitidea点击:

Call parent function which is being overridden by child during constructor chain in JavaScript(ES6)

javascriptclassconstructorthisecmascript-6

提问by andrew

I've encounter a problem below with JavaScript(ES6)

我在 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");
  }
}

What I expect is

我期望的是

foo in A is called
foo in B is called

But actually it is

但实际上是

foo in B is called
foo in B is called

I know I can resolve this by simply adding super.foo()in class B's foo function

我知道我可以通过简单地添加super.foo()B 类的 foo 函数来解决这个问题

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

But imagine a scenario similar to this:

但是想象一个类似这样的场景:

Child has to override parent's function in order to do some extra works and prevent access from outer being able to access to the original one.

子级必须覆盖父级的功能才能做一些额外的工作并防止外部访问能够访问原始功能。

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");
    };
  }
}

It seems that thisstill points to child Bwhile constructing in parent A. That's why I can't reach parent A's foo.

在 parent 中构建时似乎this仍然指向 child 。这就是为什么我无法联系到 parent的.BAAfoo

How do I make thisto call parent version function which is being overridden by child during constructor chain?

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

Or is there any better solution when it comes to scenario like this?

或者当涉及到这样的场景时有什么更好的解决方案吗?

Edit

编辑

So, after reading answers, the main question becomes --

所以,在阅读答案后,主要问题变成——

Is it discouraged to put initialize helpersor setter functionsin constructor in JavaScript since children have a chance to override them?

是否不鼓励在 JavaScript 中放入initialize helperssetter functions放入构造函数,因为孩子有机会覆盖它们?

To clarify the situation more clearly: (sorry for my previous bad example :( )

为了更清楚地澄清情况:(对不起,我以前的坏例子:()

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._divwill be undefined.

this._divundefined

Is this a bad idea since child will be able to override the function?

这是一个坏主意,因为孩子将能够覆盖该功能?

class A{
  constructor(name){
    this.setName(name); // Is it bad?
  }
  ...
}

So I shouldn't use initialize helpersor setter functionsin constructor like in Java, C++...?

所以我不应该像 Java、C++ 那样在构造函数中使用initialize helperssetter functions......?

Must I manually call things like this new A().init()to help me initialize things?

我必须手动调用这样的东西new A().init()来帮助我初始化吗?

回答by jfriend00

You seem to be operating under a misconception that there are two objects Aand Bwhen you are in the constructor of the derived class B. This is not the case at all. There is one and only one object. Both Aand Bcontribute properties and methods to that one object. The value of thiswill be the same in the constructor for Bas it is in the constructor for Aduring the creation of an object of class B.

您似乎误以为有两个对象A并且B您在派生类的构造函数中B。事实并非如此。有一个并且只有一个对象。无论AB贡献的属性和方法的一个对象。的值this在构造函数B中将与A在创建类 B 的对象期间在构造函数中相同。

The ES6 class syntax is just sugar over the ES5 method of using prototypes for object types and, in fact, the prototype is still used under the covers. As such, when you define a method fooin a derived class like you do in class B, it is still assigning to the prototype and that assignment overrides any method of the same name that might already exist on the prototype that came from the parent definition. This is why this.foo()refers to the class B version of foo. If you want to reach the class A version of foo, then you will have manually specify that using superas you appear to already know.

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

As for your specific questions:

至于你的具体问题:

It seems that this still points to child B while constructing in parent A. That's why I can't reach parent A's foo.

似乎这在父 A 中构造时仍然指向子 B。这就是为什么我无法到达父 A 的 foo。

child B and parent A are not separate objects. There is one object that both parent A and child B reference. parent A and child B methods or constructors will see the exact same value of this.

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

How do I make this to call parent version function which is being overridden by child during constructor chain?

我如何使它调用在构造函数链期间被子进程覆盖的父版本函数?

You use superto reference parent methods directly as you appear to already know.

super正如您似乎已经知道的那样,您使用直接引用父方法。

Or is there any better solution when it comes to scenario like this?

或者当涉及到这样的场景时有什么更好的解决方案吗?

superis the solution.

super是解决方案。



FYI, this is a pretty good discussion on ES6 classes including how superworks: Classes in ECMAScript 6 (final semantics). Section 4.4 seems particularly relevant to your question/understanding.

仅供参考,这是关于 ES6 类的一个很好的讨论,包括如何super工作:ECMAScript 6 中的类(最终语义)。第 4.4 节似乎与您的问题/理解特别相关。