JavaScript ES6中重写函数时如何访问子类的this?
解决子类构造中父类调用重写方法时属性未初始化的问题
这个问题其实是JavaScript类继承中实例初始化顺序导致的:当你创建ChildClass实例时,执行顺序是这样的:
- 进入
ChildClass构造函数 - 调用
super(),进入BaseClass构造函数 BaseClass构造里调用this.preHook()——这里的this其实已经是ChildClass的实例了!但问题是,此时ChildClass构造函数里super()后面的代码(也就是this.someKey = 'someValueFromChild')还没执行,所以someKey还没被赋值,自然是undefined。
知道了原因,我们可以通过调整初始化顺序来解决,这里有几个实用的方案:
方案一:父类提供显式的初始化方法,由子类控制调用时机
把父类构造里的preHook()调用移到一个单独的初始化方法中,让子类在完成自己的属性初始化后再调用:
class BaseClass { constructor() { // 不再在这里调用preHook } init() { this.preHook(); } preHook(data) { return data; } } class ChildClass extends BaseClass { constructor() { super(); this.someKey = 'someValueFromChild'; // 现在自己控制时机,调用父类的初始化方法 this.init(); } preHook(data) { console.log('this.someKey', this.someKey); // 输出this.someKey someValueFromChild } } var c = new ChildClass();
方案二:父类构造接收开关参数,延迟调用preHook
如果不想改动父类的结构太多,可以给父类构造加一个参数,控制是否自动调用preHook,子类先跳过自动调用,初始化自己的属性后再手动触发:
class BaseClass { constructor(autoRunPreHook = true) { if (autoRunPreHook) { this.preHook(); } } preHook(data) { return data; } } class ChildClass extends BaseClass { constructor() { // 传false,让父类构造不要自动调用preHook super(false); this.someKey = 'someValueFromChild'; // 手动调用preHook this.preHook(); } preHook(data) { console.log('this.someKey', this.someKey); // 输出this.someKey someValueFromChild } } var c = new ChildClass();
方案三:把属性改成getter(适合简单场景)
如果你的属性不需要动态修改,可以用getter来定义,这样即使在super()阶段访问,也能拿到正确的值:
class BaseClass { constructor() { this.preHook(); } preHook(data) { return data; } } class ChildClass extends BaseClass { constructor() { super(); } // 用getter定义someKey get someKey() { return 'someValueFromChild'; } preHook(data) { console.log('this.someKey', this.someKey); // 输出this.someKey someValueFromChild } } var c = new ChildClass();
需要注意的是,方案三只适合属性是固定值或者不需要在构造中动态赋值的场景,如果someKey需要根据参数动态设置,还是方案一或二更合适。
内容的提问来源于stack exchange,提问作者vivekfyi
相关产品推荐
相关产品推荐

