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

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

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

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

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

在父级A中构造时,this似乎仍然指向子级B。这就是为什么我无法访问父 Afoo 的原因。

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

或者遇到这种情况有什么更好的解决方案吗?

编辑

所以,看完答案后,主要问题就变成了——

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

为了更清楚地说明情况:(对我之前的坏例子感到抱歉 :( )

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

这是不是一个坏主意,因为 child 将能够覆盖该函数?

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

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

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

最佳答案

当你在派生类 B。根本不是这样。只有一个对象。 AB 都为那个对象提供属性和方法。 this 的值在 B 的构造函数中与在类的对象创建期间在 A 的构造函数中的值相同B.

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

至于您的具体问题:

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.

子 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?

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

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

super 是解决方案。


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

关于javascript - 在 JavaScript(ES6) 的构造函数链中调用被子函数覆盖的父函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32615034/

相关文章:

javascript - 使用 JavaScript 函数添加动态 HTML 内容

javascript - function() 和 new Function() 之间的区别

javascript - 解析 sdk 和 node.js 时遇到问题

python - 如何在 Python 中访问类成员变量?

javascript - 如何使用javascript修改gridview单元格值

java - Class对象A是在JVM加载A类时创建的,还是我调用A.class时创建的?

ruby - 如何让 Ruby 中的 alias_method 使用子类的自定义方法?

c++ - extern 必须有权访问类构造函数吗?

javascript - 更新 Promise 对象并宣布它的最佳方式是什么?

javascript - TinyMCE 图片上传