MST

星途 面试题库

面试题:JavaScript子类中super关键字的深度理解与应用

在JavaScript的子类构造函数和普通方法中,`super`关键字分别有什么作用?请举例说明在调用父类方法、访问父类属性以及实现多态性方面,`super`是如何发挥作用的。如果在子类构造函数中不先调用`super`就访问`this`会发生什么,为什么?
24.2万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

在JavaScript的子类构造函数中super的作用

  1. 调用父类构造函数
    • 在子类构造函数中,super用于调用父类的构造函数,以便初始化继承自父类的属性。因为在JavaScript中,子类的构造函数默认不会自动调用父类的构造函数。
    • 示例:
    class Animal {
      constructor(name) {
        this.name = name;
      }
    }
    
    class Dog extends Animal {
      constructor(name, breed) {
        super(name); // 调用父类Animal的构造函数,初始化name属性
        this.breed = breed;
      }
    }
    
    const myDog = new Dog('Buddy', 'Golden Retriever');
    console.log(myDog.name); // 输出: Buddy
    console.log(myDog.breed); // 输出: Golden Retriever
    
  2. 在访问this之前必须调用super
    • 如果在子类构造函数中不先调用super就访问this,会抛出一个错误。这是因为在调用super之前,this并未被正确初始化。JavaScript引擎需要通过super调用父类构造函数来正确设置this的原型链和初始状态。
    • 示例:
    class Animal {
      constructor(name) {
        this.name = name;
      }
    }
    
    class Dog extends Animal {
      constructor(name, breed) {
        // 下面这行会报错,因为在访问this之前没有调用super
        console.log(this); 
        super(name); 
        this.breed = breed;
      }
    }
    
    • 运行上述代码会抛出类似于“ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor”的错误。

在JavaScript的子类普通方法中super的作用

  1. 调用父类方法
    • 在子类的普通方法中,super可用于调用父类的同名方法,实现对父类方法的扩展或重写。
    • 示例:
    class Animal {
      speak() {
        return 'I am an animal';
      }
    }
    
    class Dog extends Animal {
      speak() {
        const parentSpeak = super.speak(); // 调用父类的speak方法
        return `${parentSpeak} and I am a dog`;
      }
    }
    
    const myDog = new Dog();
    console.log(myDog.speak()); // 输出: I am an animal and I am a dog
    
  2. 访问父类属性
    • 通过super,子类方法可以访问父类的属性(如果父类属性不是私有的)。不过在ES6类中,通常更常见的是调用父类方法来间接访问属性。
    • 示例:
    class Animal {
      constructor(name) {
        this.name = name;
      }
      getName() {
        return this.name;
      }
    }
    
    class Dog extends Animal {
      constructor(name, breed) {
        super(name);
        this.breed = breed;
      }
      describe() {
        const animalName = super.getName(); // 通过调用父类方法访问父类属性
        return `${animalName} is a ${this.breed}`;
      }
    }
    
    const myDog = new Dog('Buddy', 'Golden Retriever');
    console.log(myDog.describe()); // 输出: Buddy is a Golden Retriever
    
  3. 实现多态性
    • 多态性在JavaScript中通过子类重写父类方法并使用super来实现。不同的子类可以根据自身需求对父类方法进行不同的实现。
    • 示例:
    class Shape {
      calculateArea() {
        return 0;
      }
    }
    
    class Rectangle extends Shape {
      constructor(width, height) {
        super();
        this.width = width;
        this.height = height;
      }
      calculateArea() {
        return this.width * this.height;
      }
    }
    
    class Circle extends Shape {
      constructor(radius) {
        super();
        this.radius = radius;
      }
      calculateArea() {
        return Math.PI * this.radius * this.radius;
      }
    }
    
    const rectangle = new Rectangle(5, 10);
    const circle = new Circle(5);
    
    console.log(rectangle.calculateArea()); // 输出: 50
    console.log(circle.calculateArea()); // 输出: 约78.54
    
    • 在这个例子中,RectangleCircle子类都重写了Shape父类的calculateArea方法,展示了多态性。super在子类构造函数中用于初始化继承自父类的部分,而在重写的方法中可以选择是否调用父类的同名方法来进行扩展。