跳到主要内容

Javascript 继承方式

  1. 原型链继承

原型链继承通过让子类的原型指向父类的实例来实现继承。这样,子类可以继承父类的属性和方法。

function Parent() {
// 通过构造函数this ,继承属性
this.count = 1
}

// 通过原型链,继承方法
Parent.prototype.say = function () {
console.log('say:', this.count++)
}

function Child() {
// 子类构造函数中调用父类构造函数,实现属性的继承
Parent.call(this);
}
// 子类原型指向父类的实例,实现方法的继承
Child.prototype = new Parent();

const instance1 = new Child();
instance1.say(); // "say: 1"

const instance2 = new Child();
instance2.say(); // "say: 2"

优点:

  • 实现简单

缺点:

  • 当创建多个实例对象时,父类的构造函数被执行多次。
  • 无法向父类传递参数
  • 父类原型上的属性被修改,会影响所有子类属性改变。
  1. 构造函数继承(借用构造函数):

构造函数继承通过在子类构造函数中调用父类构造函数来实现继承,从而实现属性的继承。

function Parent(name) {
this.name = name || "Parent";
}

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

function Child(name) {
// 子类构造函数中调用父类构造函数,实现属性的继承
Parent.call(this, name);
}

const childObj = new Child("Child");
childObj.sayHello(); // "Hello, Child"

优点:

  • 可以通过call方法,向父类传入参数

缺点:

  • 父类与子类实例无关
  • 子类无法访问父类原型对象上的方法
  • 每个子类实例都会有父类的副本。因此,每当new一个子类实例之后,都会调用父类构造函数,重新创建父类所有属性和方法。
  1. 组合继承

组合继承结合了原型链继承和构造函数继承的优点,通过调用父类构造函数并设置子类原型为父类实例来实现继承。

function Parent() {
this.count = 1;
}

Parent.prototype.say = function () {
console.log('say:', this.count++);
}

function Child(...args) {
// this 指向父类构造函数,实现属性继承
Parent.apply(this, args)
}
// 原型链指向父类的实例,实现方法继承
Child.prototype = new Parent();

const instance = new Child('aa');
instance.say();

优点:

  • 可以通过Parent.call方法,向父类传参
  • 不存在引用属性值共享的问题

缺点

  • Parent 的构造函数被执行两次
  1. 原型式继承:

原型式继承通过创建一个临时构造函数,将传入的对象作为该构造函数的原型,从而实现继承。


const parentObj = {
name: 'Parent',
say() {
console.log('say:', this.name)
}
}

function createObj(obj) {
function F() {}
F.prototype = obj;
return new F();
}

const instance = createObj(parentObj);

instance.name = 'Child';
instance.say(); // say: Child

缺点:

  • 共享引用类型的属性,可能导致子对象修改属性时影响其他对象。
  1. 寄生式继承:

寄生式继承在原型式继承的基础上,增强了对象,返回一个新的对象。

function createObj(obj) {
const clone = Object.create(obj);
// 在对象上新增属性和方法
clone.say = function () {
console.log('say:', this.name);
}
return clone;
}

const parentObj = {
name: 'Parent'
}

const childObj = createObj(parentObj);
childObj.name = 'Child';
childObj.say() // "say: Child"

缺点:

  • 与原型式继承相似,共享引用类型的属性可能导致子对象修改属性时影响其他对象。
  1. 寄生组合式继承:

寄生组合式继承是组合继承的一种优化,避免了调用两次父类构造函数。

function Parent(name) {
this.name = name || "Parent";
}

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

function Child(name) {
// 调用父类的构造函数,实现属性的继承
Parent.call(this, name);
}

// 子类原型指向父类原型对象的副本,并实现方法的继承
Child.prototype = Object.create(Parent.prototype); // 避免子类修改父类的属性
// 重新修改子类构造函数的指向
Child.prototype.constructor = Child // 避免父类构造函数被执行两次

const childObj = new Child('Child');
childObj.say();

优点

  • 只调用一次父类的构造函数
  • 不会存在引用属性共享问题
  • 支持给父类传递参数 缺点:
  • 太复杂,不易理解