用命名函数重写类箭头函数为何不生效?问题解析
子类重写的handleClick未被调用的原因
先看你的代码核心矛盾:父类用类字段箭头函数定义handleClick,子类把它重写为原型方法,但子类的方法始终不执行。
根本原因:类字段与原型方法的优先级 + 构造函数的bind操作
- 类字段的特性:箭头函数形式的类字段,是在实例创建时(父类构造函数执行阶段)直接挂载到实例自身的属性上的。
- 原型方法的特性:子类的
handleClick原型方法,是挂载在ImageModule.prototype上的,属于原型链的一部分。JS查找属性时,会优先读取实例自身的属性,只有实例上没有该属性时,才会去原型链上找。 - bind的雪上加霜:父类构造函数里的
this.handleClick = this.handleClick.bind(this),会把父类的箭头函数绑定后(箭头函数的this本来就固定,bind实际无效,但赋值操作保留了实例属性),重新赋值给实例的handleClick。此时实例上已经有了这个属性,子类原型上的同名方法完全没机会被访问到。
具体执行步骤拆解
创建ImageModule实例时,流程是这样的:
- 先执行父类
ClickModule的构造函数:- 第一步:初始化父类的类字段
handleClick = (evt) => {},此时实例this上已经有了handleClick属性,指向父类的箭头函数。 - 第二步:执行
this.handleClick = this.handleClick.bind(this),把这个箭头函数绑定后(结果还是它自己)重新赋值给实例属性,实例上的handleClick依然指向父类的箭头函数。
- 第一步:初始化父类的类字段
- 父类构造执行完成后,子类的原型方法
handleClick虽然存在于ImageModule.prototype,但实例自身已经有了同名属性,所以调用instance.handleClick时,只会用实例上的父类箭头函数,完全不会去原型链找子类的方法。
修复方案的原理
把父类的handleClick改为普通原型方法后:
class ClickModule { constructor() { this.handleClick = this.handleClick.bind(this); } handleClick(evt) {} // 原型方法 } class ImageModule extends ClickModule { handleClick(evt) { // 子类重写的逻辑 } }
- 创建实例时,父类构造函数执行时,
this是ImageModule的实例,此时this.handleClick会通过原型链找到子类重写的原型方法; - 执行
bind(this)后,会生成一个绑定了实例this的新函数,赋值给实例的handleClick属性; - 后续调用
instance.handleClick时,执行的就是绑定后的子类方法,自然能触发你写的逻辑。
内容的提问来源于stack exchange,提问作者Maga
相关产品推荐
相关产品推荐

