MST

星途 面试题库

面试题:JavaScript 中 ES6 类继承与基于 prototype 的继承在底层实现上有何区别?

ES6 引入了 class 关键字用于实现继承,这看起来与传统基于 prototype 的继承方式不同。请深入分析 ES6 类继承与基于 prototype 的继承在底层实现机制上的差异,包括但不限于原型链的构建、方法和属性的继承过程等方面,并举例说明两者在使用场景上的不同。
35.8万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

底层实现机制差异

  1. 原型链构建
    • 基于 prototype 的继承:通过 Object.create() 方法或者直接操作 prototype 属性来构建原型链。例如:
function Animal() {
    this.species = 'animal';
}
Animal.prototype.speak = function() {
    console.log('I am an animal');
};
function Dog() {
    Animal.call(this);
    this.name = 'dog';
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
    console.log('Woof!');
};

这里 Dog.prototype 是通过 Object.create(Animal.prototype) 创建,从而建立起 DogAnimal 的原型链。 - ES6 类继承:使用 classextends 关键字,内部仍然基于原型链实现,但语法糖简化了操作。例如:

class Animal {
    constructor() {
        this.species = 'animal';
    }
    speak() {
        console.log('I am an animal');
    }
}
class Dog extends Animal {
    constructor() {
        super();
        this.name = 'dog';
    }
    bark() {
        console.log('Woof!');
    }
}

class 语法在底层同样构建原型链,Dog.prototype 会继承 Animal.prototypesuper() 用于调用父类构造函数,正确设置 this 指向等。 2. 方法和属性的继承过程 - 基于 prototype 的继承:构造函数中的属性通过 callapply 方法在子类构造函数中调用父类构造函数来继承,方法则通过原型链查找。例如上面 Dog 继承 Animalspecies 属性通过 Animal.call(this) 继承,speak 方法通过原型链查找。 - ES6 类继承:属性继承也是通过 super() 调用父类构造函数实现,方法同样基于原型链查找。但 class 语法更直观,super 关键字明确表示对父类的引用,如在 Dog 类中调用 super() 初始化父类属性。

使用场景不同

  1. 基于 prototype 的继承
    • 场景:适用于对 JavaScript 原型机制有深入理解,需要高度定制化继承行为的场景。例如在一些需要手动优化原型链,或者与旧版 JavaScript 代码紧密结合的项目中。比如编写一个高度可定制的 JavaScript 库,开发者可能希望手动控制原型链上属性和方法的继承与覆盖。
  2. ES6 类继承
    • 场景:适用于大多数现代 JavaScript 项目,尤其是注重代码可读性和简洁性的场景。例如在开发大型 Web 应用程序时,团队成员可能更熟悉面向对象的语法,class 语法更符合这种思维模式,使代码结构更清晰,易于维护和扩展。如构建一个基于 React 的组件库,使用 class 继承可以使组件之间的关系更直观。