返回

手撕代码面试高频题精讲:如何通过原型链和组合继承拆分复杂类

前端

  1. 原型链继承

原型链继承的基本思想是:利用原型让一个引用类型继承另一个引用类型的属性和方法。其基本思想是:在子类型的构造函数中调用超类型构造函数。

原型链继承的实现方式很简单,只需要在子类型的构造函数中调用父类型的构造函数,即可让子类型继承父类型的所有属性和方法。

function Parent() {
  this.name = 'Parent';
}

Parent.prototype.sayHello = function() {
  console.log('Hello, I am ' + this.name);
};

function Child() {
  Parent.call(this); // 调用父类型的构造函数
  this.age = 18;
}

Child.prototype = new Parent(); // 让子类型的原型指向父类型的实例

const child = new Child();

console.log(child.name); // Parent
console.log(child.age); // 18
child.sayHello(); // Hello, I am Parent

在上面的代码中,Child 类型继承了 Parent 类型的属性和方法。

原型链继承的优点是实现简单,并且可以实现多重继承。

原型链继承的缺点是:

  • 无法继承父类型私有属性和方法。
  • 无法控制子类型的原型。
  • 可能会导致性能问题。

2. 组合继承

组合继承指的是将原型链和借用构造函数技术组合到一块,从而发挥二者之长的一种继承模式。

基本思路:使用原型链实现对原型属性和方法的继承,通过借用构…

组合继承的实现方式如下:

function Parent() {
  this.name = 'Parent';
}

Parent.prototype.sayHello = function() {
  console.log('Hello, I am ' + this.name);
};

function Child() {
  // 调用父类型的构造函数
  Parent.call(this);
  this.age = 18;
}

// 让子类型的原型指向父类型的实例
Child.prototype = Object.create(Parent.prototype);
// 重写子类型原型上的构造函数
Child.prototype.constructor = Child;

const child = new Child();

console.log(child.name); // Parent
console.log(child.age); // 18
child.sayHello(); // Hello, I am Parent

在上面的代码中,Child 类型继承了 Parent 类型的属性和方法。

组合继承的优点是:

  • 可以继承父类型私有属性和方法。
  • 可以控制子类型的原型。
  • 不会导致性能问题。

组合继承的缺点是实现复杂,并且无法实现多重继承。

3. 原型链继承与组合继承的异同

原型链继承和组合继承都是实现对象继承的两种方式,但它们之间也存在一些异同。

相同点:

  • 都是通过在子类型中调用父类型的构造函数来实现继承。
  • 都会让子类型继承父类型的所有属性和方法。

不同点:

  • 原型链继承是通过在子类型的原型中指向父类型的实例来实现继承,而组合继承是通过在子类型中调用父类型的构造函数并修改子类型的原型来实现继承。
  • 原型链继承可以实现多重继承,而组合继承无法实现多重继承。
  • 原型链继承无法继承父类型私有属性和方法,而组合继承可以继承父类型私有属性和方法。
  • 原型链继承可能会导致性能问题,而组合继承不会导致性能问题。

4. 如何选择原型链继承或组合继承

原型链继承和组合继承各有优缺点,因此在实际开发中应该根据具体情况选择使用哪种继承方式。

如果需要继承父类型私有属性和方法,或者需要控制子类型的原型,或者需要避免性能问题,那么可以使用组合继承。

如果需要实现多重继承,或者实现简单,那么可以使用原型链继承。

5. 总结

原型链继承和组合继承都是实现对象继承的两种方式,它们各有优缺点。在实际开发中应该根据具体情况选择使用哪种继承方式。