先看其它总结文章:
- juejin.cn/post/703922…
- 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();
看下面在浏览器中运行的截图:
执行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();
按照例子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();
如果将父类的方法改成箭头函数,会发生什么?当调用到父类的this.boo()时,this指向是子类,那调子类的boo()为什么没输出 2 'b',反而是 1 'a'?因为这段代码父类的boo是使用箭头函数定义的,boo在实例属性而非原型上,那么子类继承父类,则继承的是父类的boo属性,子类定义的boo在子类的原型上。根据属性的查找机制,属性 > 原型,则会走到箭头函数中,所以输出1而非2
为什么会举这个例子3呢,本人在最近的工作需求中,将一个react类组件中定义的函数,由普通方法改为了箭头函数,本意是为了避免在react类式组件中bind(this)的问题,结果改的那个组件,被其它组件继承了,又恰好重写了我改的方法,结果就是调用不走子类重写的方法了,还是挺坑的,记录一下。
另外就是,当时遇到这个坑时,感觉现在写react类组件基本都是箭头函数啊,这样岂不是很容易踩这个坑,查了一下react官方文档: