如何判断JavaScript基类方法是否被子类通过super.method()调用?
如何判断基类中的方法是否被直接调用?
假设存在如下代码:
class Base { myMethod() {} } class Child1 extends Base { myMethod() {} } class Child2 extends Base { myMethod() { super.myMethod(); } } class Child3 extends Base {} // extending another Child class Child4 extends Child2 {}
需求
若子类或其除Base外的父类未实现该方法,则从Base.myMethod中抛出错误,具体表现如下:
let c1 = new Child1(); c1.myMethod(); // Method found on instance, works let c2 = new Child2(); c2.myMethod(); // Method found on instance, calls super method (on Base), works let c3 = new Child3(); c3.myMethod(); // No method found on instance, Base class throws an error let c4 = new Child4(); c4.myMethod(); // No method found on instance but is found on parent (Child2), thus works
简言之:仅当Base的myMethod被直接调用(调用栈中无super.myMethod())时抛出错误,该如何实现这一判断?
解决方案
推荐通过遍历实例的原型链,判断首个拥有myMethod的原型对象是否为Base.prototype,这种方式兼容性强且逻辑可靠。
修改Base类的myMethod如下:
class Base { myMethod() { let currentProto = Object.getPrototypeOf(this); // 向上遍历原型链,找第一个自身定义了myMethod的对象 while (currentProto) { if (currentProto.hasOwnProperty('myMethod')) { // 若找到的不是Base的原型,说明有子类实现了方法,正常执行 if (currentProto !== Base.prototype) { return; } // 否则就是直接调用基类方法,抛出错误 break; } currentProto = Object.getPrototypeOf(currentProto); } throw new Error('Method must be implemented by a subclass'); } }
原理说明
- 调用
myMethod时,从当前实例的原型开始向上遍历原型链 - 找到第一个自身拥有
myMethod属性的原型对象:- 若该对象不是
Base.prototype,说明存在子类(或子类的子类)实现了方法,即使通过super调用过来也允许执行 - 若该对象就是
Base.prototype,说明没有任何子类实现该方法,属于直接调用基类方法,抛出错误
- 若该对象不是
测试后完全符合需求:
Child1实例调用:找到Child1.prototype的myMethod,正常执行Child2实例调用:找到Child2.prototype的myMethod,正常执行(即使调用了super)Child3实例调用:遍历到Base.prototype才找到方法,抛出错误Child4实例调用:遍历到Child2.prototype的myMethod,正常执行
另外也可以通过调用栈判断(兼容性稍差,依赖浏览器调用栈格式):
class Base { myMethod() { const stack = new Error().stack; // 检查调用栈中是否存在super.myMethod的调用痕迹 if (!stack.includes('super.myMethod')) { throw new Error('Method must be implemented by a subclass'); } } }
内容的提问来源于stack exchange,提问作者Fygo
相关产品推荐
相关产品推荐

