为什么子类继承父类的时候,子类重写的普通函数不会覆盖父类的箭头函数?

AnbolKing
  • 3
新手上路,请多包涵

如下面这段代码

class Animal { 
  sayName = () => {
    console.log('I hate coding') 
  }
}
class Monkey extends Animal { 
  sayName() { 
    console.log('I love coding'); 
  } 
}
const monkey = new Monkey(); 
monkey.sayName();

为什么输出会是I hate coding,但是如果Animal中的sayName是普通函数,输出就是I love coding

回复
阅读 434
4 个回答

因为箭头函数的语法其实是this.sayName = this.sayName.bind(this)的语法糖。
如果你写过class API 的react,可能会知道在之前的react中,对于函数的绑定需要在constructor中进行this.fn = this.fn.bind(this)的上下文绑定.于是后来babel支持了这种箭头函数的快捷写法,实际上两种写法是等同的。而正常规范里的class方法是绑定在prototype上的,也就是ES5中Animal.prototype.sayName = function(){}这样子的写法。
image
如图所示,箭头函数sayName是绑定在实例上的,非箭头函数是在proto上的,这便是为什么输出是父类的log,你可以理解为箭头函数实际上是等同于先new一个对象之后再对该实例对象赋值方法
image
image

从面向对象的设计角度来看,可重载的方法应是类的,非静态变量应是实例的。JavaScript 在实现时采用的是 Prototype 的方式。方法声明实际上是关联到父类的__proto__变量属性上,而变量则不是。

箭头函数实际是匿名函数(闭包),赋值给了 sayName 变量。在调用函数时,一个对象先在直接属性里找,找不到会沿着继承链向上的__proto__里找。

console.log(monkey)

可以看到:

image

image.png

Class 'Animal' defines instance member property 'sayName', but extended class 'Monkey' defines it as instance member function.

TS 的报错已经一目了然了

因为一个是字段一个是方法,方法在原型上,字段在 this 上,所以你的子类的方法并没有覆盖父类的字段定义。

你知道吗?

宣传栏