Skip to content

1. 继承

  • 现实中的继承:子承父业,比如我们都继承了父亲的姓。
  • 程序中的继承:子类可以继承父类的—些属性和方法。

使用 extends 关键字实现继承

js
class Son extends Father {
    // class body
}
class Son extends Father {
    // class body
}

2. super 关键字

super 关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。

js
super([arguments]);
// 调用 父对象/父类 的构造函数

super.functionOnParent([arguments]);
// 调用 父对象/父类 上的方法
Copy to clipboardErrorCopied
super([arguments]);
// 调用 父对象/父类 的构造函数

super.functionOnParent([arguments]);
// 调用 父对象/父类 上的方法
Copy to clipboardErrorCopied

示例:

js
class Person {
    constructor (uname, age) {
        this.uname =uname;
        this.age = age;
    }
}
class Student extends Person {
    constructor (uname, age, major) {
        // super 将子类的参数传递给父类构造函数,减少代码量
        super(uname, age);
        // 子类可以有自己独有的属性
        this.major = major;
    }
}
let rick = new Student("Rick", 22, "数学");
class Person {
    constructor (uname, age) {
        this.uname =uname;
        this.age = age;
    }
}
class Student extends Person {
    constructor (uname, age, major) {
        // super 将子类的参数传递给父类构造函数,减少代码量
        super(uname, age);
        // 子类可以有自己独有的属性
        this.major = major;
    }
}
let rick = new Student("Rick", 22, "数学");

WARNING

注意: 子类在构造函数中使用 super, 必须放到 this 前面(必须先调用父类的构造方法,再使用子类构造方法)

3. super 传值问题

观察以下代码,运行将产生错误。

js
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
}
class Son extends Father {
    constructor(x, y) {
        this.x = this.x;
        this.y = this.y;
    }
}
let obj = new Son(10, 20);
obj.sum();
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
}
class Son extends Father {
    constructor(x, y) {
        this.x = this.x;
        this.y = this.y;
    }
}
let obj = new Son(10, 20);
obj.sum();

解释说明:若子类没有写构造函数 constructor,则实例化时默认调用父类的,这时候程序运行无误。若子类写了构造函数,那么子类在调用 sum 方法的时候,参数的值没有传给父类,父类无法调用参数的值,也就无法执行 sum 方法。

正确:加入 super。

js
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
}
class Son extends Father {
    constructor(x, y) {
        super(x, y);
    }
}
let obj = new Son(10, 20);
obj.sum(); // 30
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
}
class Son extends Father {
    constructor(x, y) {
        super(x, y);
    }
}
let obj = new Son(10, 20);
obj.sum(); // 30

4. super 调用父类普通函数

js
class Parent {
    sayHi() {
        return "Father: hello";
    }
}
class Child extends Parent {
    sayHi() {
        // super 调用父类普通函数
        console.log(super.sayHi());
    }
}
let man = new Child();
man.sayHi(); // Father: hello
class Parent {
    sayHi() {
        return "Father: hello";
    }
}
class Child extends Parent {
    sayHi() {
        // super 调用父类普通函数
        console.log(super.sayHi());
    }
}
let man = new Child();
man.sayHi(); // Father: hello

5. 继承中属性和方法查找原则

继承中的属性或者方法查找原则:就近原则

  • 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
  • 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
js
class Parent {
    sayHi() {
        console.log("Father: hello");
    }
}
class Child extends Parent {
    sayHi() {
        console.log("Son: hello");
    }
}
let man = new Child();
man.sayHi(); // Son: hello
class Parent {
    sayHi() {
        console.log("Father: hello");
    }
}
class Child extends Parent {
    sayHi() {
        console.log("Son: hello");
    }
}
let man = new Child();
man.sayHi(); // Son: hello

6. super 必须放到子类 this 之前

子类在构造函数中使用 super, 必须放到 this 前面。

js
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}
class Son extends Father {
    constructor(x, y, z) {
        super(x, y, z);
        this.z = this.z;
    }
}
let obj = new Son();
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}
class Son extends Father {
    constructor(x, y, z) {
        super(x, y, z);
        this.z = this.z;
    }
}
let obj = new Son();

使用类的注意点

  • 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象
  • 类里面的共有属性和方法一定要加 this 使用
  • 类里面的 this 指向问题:constructor 里面的 this 指向实例对象, 方法里面的 this 指向这个方法的调用者