MST

星途 面试题库

面试题:JavaScript继承机制中的寄生组合式继承及其优势

详细阐述JavaScript中寄生组合式继承的原理,与其他继承方式(如原型链继承、借用构造函数继承等)相比,它具有哪些显著优势?请通过代码示例进行对比说明。
49.9万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

寄生组合式继承原理

  1. 基础概念:寄生组合式继承是一种实现JavaScript继承的模式,它结合了寄生式继承和组合继承的优点。核心思想是通过创建一个中间函数,让这个中间函数的原型指向父类的原型,从而实现原型链的继承,同时又避免了组合继承中重复调用父类构造函数的问题。
  2. 实现步骤
    • 首先创建一个临时的构造函数。
    • 然后将这个临时构造函数的原型指向父类的原型。
    • 创建一个新对象,这个新对象的原型是上述临时构造函数的实例,这样新对象就拥有了父类原型上的属性和方法。
    • 最后在子类的构造函数中调用父类的构造函数,以确保子类实例拥有父类实例的属性。

与其他继承方式相比的优势

  1. 与原型链继承相比
    • 原型链继承问题:原型链继承会导致所有实例共享原型对象上的属性,如果原型对象上的属性是引用类型,一个实例对其修改会影响其他实例。例如:
function Animal() {}
Animal.prototype.species = '动物';
function Dog() {}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
let dog1 = new Dog();
let dog2 = new Dog();
dog1.species = '犬科';
console.log(dog2.species); // '犬科',共享导致影响
- **寄生组合式继承优势**:通过在子类构造函数中调用父类构造函数,为每个子类实例单独创建属性,避免了共享引用类型属性的问题。

2. 与借用构造函数继承相比: - 借用构造函数继承问题:借用构造函数继承无法继承父类原型上的属性和方法,因为它只是在子类构造函数中调用父类构造函数,没有建立原型链关系。例如:

function Animal(name) {
    this.name = name;
}
Animal.prototype.speak = function() {
    console.log(this.name + '发出声音');
};
function Dog(name) {
    Animal.call(this, name);
}
let dog = new Dog('旺财');
dog.speak(); // Uncaught TypeError: dog.speak is not a function
- **寄生组合式继承优势**:既通过调用父类构造函数初始化实例属性,又通过设置原型链继承了父类原型上的属性和方法。

代码示例对比

  1. 原型链继承
function Parent() {
    this.value = 10;
}
Parent.prototype.getValue = function() {
    return this.value;
};
function Child() {}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
let child1 = new Child();
let child2 = new Child();
child1.value = 20;
console.log(child2.getValue()); // 20,共享属性问题
  1. 借用构造函数继承
function Parent(name) {
    this.name = name;
}
Parent.prototype.sayName = function() {
    console.log('我是' + this.name);
};
function Child(name) {
    Parent.call(this, name);
}
let child = new Child('小明');
child.sayName(); // Uncaught TypeError: child.sayName is not a function
  1. 寄生组合式继承
function Parent(name) {
    this.name = name;
}
Parent.prototype.sayName = function() {
    console.log('我是' + this.name);
};
function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}
function inheritPrototype(child, parent) {
    let prototype = Object.create(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}
inheritPrototype(Child, Parent);
let child = new Child('小红', 18);
child.sayName(); // 我是小红