extends 关键字

我们之前使用过原型实现继承,而类中有个 extends 关键字可以直接实现继承。

与原型继承中学到的知识点一致,继承时 子类.prototype.[[prototype]] === 父类.prototype

$$jsdemo$$
$$edit$$
class Animal {
    sleep() {
        alert("睡觉")
    }
}

class Cat extends Animal {
    eat() {
        alert("吃鱼")
    }
}

alert(Cat.prototype.__proto__ === Animal.prototype) // true

const cat = new Cat()
cat.eat() // 吃鱼
cat.sleep() // 睡觉

此时的 Animal 被称为父类,而 Cat 被称为子类。

super 关键字

使用 super 可以调用父类的方法,特别是某些方法被子类重写的情况下。

$$jsdemo$$
$$edit$$
class Animal {
    sleep() {
        alert("睡觉")
    }
}

class Cat extends Animal {
    eat() {
        alert("吃鱼")
    }
    sleep() {
        alert("躺在猫爬架上")
        super.sleep()
    }
}

const cat = new Cat()

// 躺在猫爬架上
// 睡觉
cat.sleep()

$$tip

this 类似,箭头函数同样没有 super

$$

class Animal {
    sleep() {
        alert("睡觉")
    }
}

class Cat extends Animal {
    eat() {
        alert("吃鱼")
    }
    sleep() {
        alert("躺在猫爬架上")

        // setTimeout(function () {
        //     super.sleep() // Uncaught SyntaxError: 'super' keyword unexpected here
        // }, 100)

        setTimeout(() => {
            super.sleep() // ok
        }, 100)
    }
}

const cat = new Cat()

// 躺在猫爬架上
// 睡觉
cat.sleep()

重写 constructor

在没有重写 constructor 的情况下,会自动生成一个执行 super(…args) (实例化父类,并执行父类的构造方法)的 constructor

$$jsdemo$$
$$edit$$
class Animal {
    constructor(name) {
        this.name = name
    }

    sleep() {
        alert(`${this.name}在睡觉`)
    }
}

class Cat extends Animal {
    // 没定义构造方法的情况下
    // 会默认生成以下的方法
    // constructor(...args) {
    //     super(...args)
    // }
    eat() {
        alert(`${this.name}在吃鱼`)
    }
}

const cat = new Cat("喵喵")
cat.eat() // 喵喵在吃鱼

以下例子手动调用了父类的构造函数。

class Animal {
    constructor(name) {
        this.name = name
    }

    sleep() {
        alert("睡觉")
    }
}

class Cat extends Animal {
    constructor(name, title) {
        super(name)

        this.title = title
        
        // super(name) // 错误,必须在派生(子)类的构造函数中的 this 或 return 语句前执行 super 。
    }

    eat() {
        alert(`【${this.title}】,${this.name}在吃鱼`)
    }
}

const cat = new Cat("喵喵", "擒鼠者")
cat.eat() // 【擒鼠者】,喵喵在吃鱼

练习

  1. 补全以下代码。
class Animal {
    constructor(name) {
        this.name = name
    }

    get hello() {
        return `我叫${this.name}。`
    }
}

class Cat extends Animal {
    // 补全代码
}

class Dog extends Animal {
    // 补全代码
}

const cat = new Cat(5, "喵喵")
alert(cat.hello) // 我叫喵喵。今年5岁。

const dog = new Dog({
    name: "旺财",
    food: "排骨",
})
alert(dog.hello) // 我叫旺财。喜欢吃排骨。

$$answer

$$jsdemo$$
$$edit$$
class Animal {
        constructor(name) {
            this.name = name
        }

        get hello() {
            return `我叫${this.name}。`
        }
    }

    class Cat extends Animal {
        constructor(age, name) {
            super(name)

            this.age = age
        }

        get hello() {
            return `${super.hello}今年${this.age}岁。`
        }
    }

    class Dog extends Animal {
        constructor({ name, food }) {
            super(name)

            this.food = food
        }

        get hello() {
            return `${super.hello}喜欢吃${this.food}。`
        }
    }

    const cat = new Cat(5, "喵喵")
    alert(cat.hello) // 我叫喵喵。今年5岁。

    const dog = new Dog({
        name: "旺财",
        food: "排骨",
    })
    alert(dog.hello) // 我叫旺财。喜欢吃排骨。

$$