为什么继承需要调用 super()

在子类 constructor 中必须调用 super 方法,因为子类没有自己的 this 对象,而是继承在父类的 this 对象,然后对其进行加工,而 super 就代表了父类的构造函数。

在下面的例子中,super 虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指的是 B,因此 super() 在这里相当于A.prototype.constructor.call(this, props)

// 父类
class People {
    constructor(name) {
        this.name = name
    }
    eat() {
        console.log(`${this.name} eat something`)
    }
}
 
// 子类
class Student extends People {
    constructor(name, number) {
        super(name)
        this.number = number
    }
    sayHi() {
        console.log(`姓名 ${this.name} 学号 ${this.number}`)
    }
}
 
// 子类
class Teacher extends People {
    constructor(name, major) {
        super(name)
        this.major = major
    }
    teach() {
        console.log(`${this.name} 教授 ${this.major}`)
    }
}
 
// 实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
xialuo.eat()
 
// 实例
const wanglaoshi = new Teacher('王老师', '语文')
console.log(wanglaoshi.name)
console.log(wanglaoshi.major)
wanglaoshi.teach()
wanglaoshi.eat()

原型

JavaScript 常被描述为一种基于原型的语言 —— 每个对象都有一个原型对象。

当试图访问一个对象属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

  1. 每个 class 都有一个显示原型 prototype
  2. 每个实例都有隐式原型 _proto_
  3. 每个 _proto_ 指向对应 class 的 prototype

基于原型的执行规则

  1. 获取属性 xialuo.name 或执行方法 xialuo.sayHi() 时
  2. 先在自身属性和方法寻找
  3. 如果找不到则自动去 _proto_ 中查找 基于原型的执行规则.png

原型链

原型对象也可能拥有原型,并从中继承方法和属性,一层一层、依次类推。这种关系常常被称为原型链(prototype chain),它解释了为何一个对象会拥有定义在其它对象中的属性和方法。 原型和原型链.png```