JavaScript父类方法中this指向子类引发继承异常的惯用解决方法问询
解决JS继承中父类方法调用子类重写方法的问题
这个问题其实是JavaScript继承中this绑定特性导致的典型坑——父类方法里的this永远指向当前实例(也就是子类实例),所以当你在父类createObject里调用this.createObject时,实际上触发的是子类B重写后的版本,自然返回的是ID而非对象,后续赋值object.type就报错了。
下面给你两个符合JavaScript惯用写法的解决方案:
方案1:直接调用父类原型上的方法(快速修复)
在父类A的createObject方法中,把递归调用的this.createObject改成直接调用父类原型上的方法,并用call绑定当前实例的this,这样就能绕过子类的重写:
class A{ createObject(type) { let object = null; for (let i in this.objecttypes) { if (this.objecttypes[i].type == type) { if (this.objecttypes[i].template) { // 直接调用父类原型的方法,绑定当前this object = A.prototype.createObject.call(this, this.objecttypes[i].template); object.type = type; } else object = new TestObject(type); for (const aname in this.objecttypes[i].attributes) object.set(aname, this.objecttypes[i].attributes[aname]); } } return object; } }
原理:A.prototype.createObject是父类原始的方法定义,用call(this, ...)可以确保执行时this依然指向当前子类实例(这样能正确访问到this.objecttypes等实例属性),但调用的是父类的方法逻辑,不会触发子类的重写,所以返回的是对象而非ID。
方案2:拆分核心逻辑与对外接口(更优雅的架构)
把父类中负责对象创建的核心逻辑抽成一个不会被重写的内部方法(比如命名为_createObjectCore),父类的createObject只作为对外接口调用这个核心方法;子类重写createObject时,依然通过super.createObject调用父类接口,而父类内部递归调用核心方法,从根源上避免冲突:
// 父类A class A{ // 核心创建逻辑,用下划线标识内部方法(约定俗成不会被重写) _createObjectCore(type) { let object = null; for (let i in this.objecttypes) { if (this.objecttypes[i].type == type) { if (this.objecttypes[i].template) { // 递归调用核心方法,而非对外的createObject object = this._createObjectCore(this.objecttypes[i].template); object.type = type; } else object = new TestObject(type); for (const aname in this.objecttypes[i].attributes) object.set(aname, this.objecttypes[i].attributes[aname]); } } return object; } // 对外接口 createObject(type) { return this._createObjectCore(type); } } // 子类B class B extends A{ createObject(type, otherargs){ // 调用父类的对外接口,内部会走核心逻辑 let object = super.createObject(type); this.objects.set(object.id, object); /* do things with otherargs */ return object.id; } }
这个方案更符合代码设计原则:把核心逻辑和对外暴露的接口分离,子类只需要重写对外接口来扩展功能,不会影响父类内部的递归逻辑,后续维护也更清晰。
内容的提问来源于stack exchange,提问作者Marius
相关产品推荐
相关产品推荐

