ES6访问子类';在javascript中重写函数时使用“this”

ES6访问子类';在javascript中重写函数时使用“this”,javascript,ecmascript-6,Javascript,Ecmascript 6,我有以下代码: class BaseClass { constructor() { // BELOW LINE CALLS OVERRIDDEN FUNCTION BUT WITH `this` OF BaseClass this.preHook(); } // THIS FUNCTION IS BEING OVERRIDDEN IN CHILD CLASS preHook(data) { return data; } } class Child

我有以下代码:

class BaseClass {
  constructor() {
    // BELOW LINE CALLS OVERRIDDEN FUNCTION BUT WITH `this` OF BaseClass
    this.preHook(); 
  }

  // THIS FUNCTION IS BEING OVERRIDDEN IN CHILD CLASS
  preHook(data) {
   return data;
  }
}


class ChildClass extends BaseClass {
   constructor() {
     super();
     this.someKey = 'someValueFromChild';
   }
   preHook(data) {
      console.log('this.someKey', this.someKey); //IT PRINTS undefined
   }
}


var c = new ChildClass();

OUTPUT:
this.someKey undefined

Expecting
this.someKey someValueFromChild
因此,在基类的构造函数中,我调用了一个函数this.preHook(),该函数在ChildClass中被重写,当我们初始化ChildClass时,它调用基类的构造函数,然后调用this.preHook的重写版本,而不是打印在ChildClass中定义的
someValueFromChild
,它正在打印未定义的内容(它使用父类的
而不是子类的

如何使用子类的

如何使用子类的

没有子类的“
this
”。只有一个对象(由其原型对象支持)。
基类中的
this
子类中的
this
都指同一个对象

访问
this.someKey
会导致该代码中的
未定义
,原因是子构造函数直到父构造函数完成后才设置
someKey
,并且父构造函数调用
preHook
,因此在子构造函数设置之前调用
preHook
someKey
。因此,当
preHook
尝试从对象读取它时,根本就没有
someKey
属性。如果使用调试器逐步执行代码,您会看到这一点。下面是一个注释版本,显示了在以下情况下发生的情况:

类基类{
构造函数(){
log(“基类构造函数启动”);
这个;
log(“基类构造函数完成”);
}
//正在子类中重写此函数
预读(数据){
log(“调用BaseClass.preHook”);
返回数据;
}
}
类ChildClass扩展了基类{
构造函数(){
log(“子类构造函数启动”);
超级();
log(“ChildClass构造函数设置'someKey`”);
this.someKey='someValueFromChild';
log(“子类构造函数完成”);
}
预读(数据){
log(“调用ChildClass.preHook”);
log('this.someKey',this.someKey);
}
}
var c=new ChildClass();
。作为控制台包装器{
最大高度:100%!重要;
}
如何使用子类的

没有子类的“
this
”。只有一个对象(由其原型对象支持)。
基类中的
this
子类中的
this
都指同一个对象

访问
this.someKey
会导致该代码中的
未定义
,原因是子构造函数直到父构造函数完成后才设置
someKey
,并且父构造函数调用
preHook
,因此在子构造函数设置之前调用
preHook
someKey
。因此,当
preHook
尝试从对象读取它时,根本就没有
someKey
属性。如果使用调试器逐步执行代码,您会看到这一点。下面是一个注释版本,显示了在以下情况下发生的情况:

类基类{
构造函数(){
log(“基类构造函数启动”);
这个;
log(“基类构造函数完成”);
}
//正在子类中重写此函数
预读(数据){
log(“调用BaseClass.preHook”);
返回数据;
}
}
类ChildClass扩展了基类{
构造函数(){
log(“子类构造函数启动”);
超级();
log(“ChildClass构造函数设置'someKey`”);
this.someKey='someValueFromChild';
log(“子类构造函数完成”);
}
预读(数据){
log(“调用ChildClass.preHook”);
log('this.someKey',this.someKey);
}
}
var c=new ChildClass();
。作为控制台包装器{
最大高度:100%!重要;

}
存在一种竞争条件,即ES6类的自然限制的结果。
应始终出现在子构造函数中的
super()
之后。因为
此.preHook()
在父构造函数中调用(
super
),无法在构造函数中分配
this.someKey
并在
this.preHook()调用期间显示

否则,
this.preHook()
调用应该只在子构造函数中发生,这违背了钩子的概念,并阻止了子类的正确扩展

为了避免竞争条件,应该在类原型上定义
someKey
,因此
super
这个
优先级不再是问题:

class ChildClass extends BaseClass {
   constructor() {
     super();
   }

    get someKey() {
      return 'someValueFromChild';
    }
    ...
}
允许维护适当类生命周期的另一种方法是在应用程序级别实现钩子,就像在JS框架中通常做的那样。可钩子类应该通过特定接口实例化,而不是直接实例化,即:

function instantiateWithHooks(cls, args) {
  const instance = new cls(...args);
  instance.preHook();
  return instance;
}

正如另一个答案中所解释的,当实例化子类时,只有一个
this
,它(通常)是子类的实例。

存在一个竞争条件,即ES6类的自然限制的结果。
this
应该总是出现在
super()之后
在子构造函数中。由于在父构造函数(
super
)中调用了
this.preHook()
),因此无法在构造函数中分配
this.preHook()
并在
此.preHook()调用期间显示

否则,
this.preHook()
调用应该只在子构造函数中发生,这违背了钩子的概念,并阻止了子类的正确扩展

为了避免竞争条件,应该在类原型上定义
someKey
,因此<