JavaScript中调用其他实例父类方法的方案及优缺点分析
我构建了如下代码结构:
class Parent { constructor(id){ this.id = id; this.partner = null; } fn(x) { console.log(`Parent:${this.id}:fn(${x})`); } } class Child extends Parent { constructor(id){ super(id); } fn(x) { console.log(`Child:${this.id}:fn(${x})`); super.fn(x); console.log(' -> calling partner'); // Trigger partner too (**** this is key line I'm asking about) Object.getPrototypeOf(Object.getPrototypeOf(this.partner)).fn.call(this.partner, x); } setPartner(partner){ this.partner = partner; } } a = new Child('a'); b = new Child('b'); a.setPartner(b); b.setPartner(a); a.fn('test a'); console.log(''); b.fn('test b');
在此场景中,类实例调用另一个实例的方法时,为避免无限循环,我直接调用了父类方法。我的问题是:是否存在其他合理的方式调用另一个实例的父类方法?
撰写问题时,我意识到通过拆分出_fn方法可以更简洁地解决底层问题,但仍希望了解调用父类方法的各类可行方案。另外我原本尝试使用__proto__.__proto__但未成功,也想知道是否可以通过super来实现类似super.fn.call(this, x)的调用。
拆分方法的代码如下:
class Parent { constructor(id){ this.id = id; this.partner = null; } fn(x) { console.log(`Parent:${this.id}:fn(${x})`); } } class Child extends Parent { constructor(id){ super(id); } _fn(x) { console.log(`Child:${this.id}:fn(${x})`); super.fn(x); } fn(x) { this._fn(x); console.log(' calling partner ->'); this.partner._fn.call(this.partner, x); } setPartner(partner){ this.partner = partner; } } a = new Child('a'); b = new Child('b'); a.setPartner(b); b.setPartner(a); a.fn('test a'); console.log(''); b.fn('test b');
可行方案汇总
直接引用父类原型方法
这是最简洁直观的方式,直接调用Parent.prototype.fn并通过call指定上下文:Parent.prototype.fn.call(this.partner, x);无需操作实例的原型链,直接明确指向父类的方法,可读性和维护性都很强。
通过子类原型获取父类原型
如果不想直接引用Parent类(比如模块化场景下父类未暴露),可以通过Child的原型来获取父类原型:Object.getPrototypeOf(Child.prototype).fn.call(this.partner, x);这种方式避免了两次调用
Object.getPrototypeOf获取实例的原型链,效率更高。关于
__proto__.__proto__的问题
你之前尝试的__proto__.__proto__理论上是可行的,写法如下:this.partner.__proto__.__proto__.fn.call(this.partner, x);但
__proto__是非标准属性(虽被主流浏览器支持),不推荐在生产环境使用,优先使用标准的Object.getPrototypeOf方法。关于
super的使用限制
不能通过super实现跨实例调用父类方法。super只能在类的方法内部使用,它的指向是当前类的父类原型,且上下文绑定的是当前实例,无法通过call/apply改变super的上下文指向,因此super.fn.call(this.partner, x)这种写法是无效的。拆分方法(推荐)
你自己想到的拆分_fn方法的方案,是更优雅的工程化解决方案。它把业务逻辑和对外调用解耦,既避免了循环调用,也无需直接操作原型链,代码结构更清晰,维护成本更低,推荐在实际项目中优先使用。
内容的提问来源于stack exchange,提问作者Jules

