es6中的class继承

64 阅读2分钟

先看其它总结文章:

  1. juejin.cn/post/703922…
  2. juejin.cn/post/684490… (有点长,可先不看)

简述

  • 使用extends继承,子类会继承父类的实例属性、静态属性和方法
  • 子类需要在constructor中首先调用super(),再写别的逻辑。super()会执行父类的constructor方法
  • 思考:如果在子类重写父类的方法,执行时是怎么样的?

举例1

class Fa {
 aaa = 'aaa';
 static bbb = 'bbb';
 
 constructor() {
   this.boo();
 }

 boo() {
   console.log('Fa的boo', this.aaa);
 }
}

class Son extends Fa {
 constructor() {
   super();
 }
 boo() {
     console.log('Son的boo', this.aaa)
 }
}

const b = new Son();

看下面在浏览器中运行的截图:

image.png 执行const b = new Son()时,执行Son的constructor方法,调用super(),继续执行Fa的constructor方法,执行第6行-this.boo(),此时的this指向的是Son,因此执行第19行。 再去看b的实例上现在都有什么,发现有aaa实例属性(继承自父类), b的原型链上还分别能找到重写的boo和父类的boo方法。如果子类没有重写父类的boo,则会调用父类的。——> 原型链的查找机制

举例2

class Fa {
 aaa = 'a'
 constructor() {
   this.boo();
   console.log(this.aaa);
 }

 boo() {
   console.log(1, this.aaa);
 }
}

class Son extends Fa {
 aaa = 'b'
 constructor() {
   super();
   console.log(this.aaa);
 }

 boo() {
   console.log(2, this.aaa);
 }
}

const b = new Son();

image.png 按照例子1中的说法,运行new Son()中的super(),调用Fa中的constructor,this指向指向的是Son,那为什么this.aaa会输出'a'?因为此时son的实例还没有初始化,super()调用结束才会初始化完成。初始化顺序,先父类后子类(调用super时会先初始化父类)

举例3

class Fa {
 aaa = 'a'
 constructor() {
   this.boo();
   console.log(this.aaa);
 }

 boo = () => {
   console.log(1, this.aaa);
 }
}

class Son extends Fa {
 aaa = 'b'
 constructor() {
   super();
   console.log(this.aaa);
 }

 boo() {
   console.log(2, this.aaa);
 }
}

const b = new Son();

image.png 如果将父类的方法改成箭头函数,会发生什么?当调用到父类的this.boo()时,this指向是子类,那调子类的boo()为什么没输出 2 'b',反而是 1 'a'?因为这段代码父类的boo是使用箭头函数定义的,boo在实例属性而非原型上,那么子类继承父类,则继承的是父类的boo属性,子类定义的boo在子类的原型上。根据属性的查找机制,属性 > 原型,则会走到箭头函数中,所以输出1而非2

为什么会举这个例子3呢,本人在最近的工作需求中,将一个react类组件中定义的函数,由普通方法改为了箭头函数,本意是为了避免在react类式组件中bind(this)的问题,结果改的那个组件,被其它组件继承了,又恰好重写了我改的方法,结果就是调用不走子类重写的方法了,还是挺坑的,记录一下。

另外就是,当时遇到这个坑时,感觉现在写react类组件基本都是箭头函数啊,这样岂不是很容易踩这个坑,查了一下react官方文档:

image.png