返回

解析JavaScript的多样继承机制

前端

您对JavaScript继承策略的了解可能止步于原型链,但JavaScript的继承策略,除了原型链,还有另外5种。

JavaScript的继承策略多种多样,包括原型链继承、经典继承、组合继承、原型式继承、寄生式继承和寄生组合式继承。掌握这些多样继承策略可以让你更灵活高效地处理对象关系问题。

原型链继承

JavaScript使用原型链来实现继承,父对象的原型作为子对象的原型,从而建立起原型链。子对象可以访问父对象的所有属性和方法,但是父对象不能访问子对象。

// 父对象
const Person = {
  name: 'John',
  age: 30,
  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

// 子对象
const Student = {
  // 通过设置原型关联到父对象
  __proto__: Person,
  major: 'Computer Science',
  study() {
    console.log(`I am studying ${this.major}.`);
  }
};

const student = Object.create(Student);
student.name = 'Alice';
student.age = 20;
student.greet(); // Hello, my name is Alice and I am 20 years old.
student.study(); // I am studying Computer Science.

经典继承

经典继承,也称为基于原型的继承,使用new创建一个新的对象,新对象继承父对象的所有属性和方法。经典继承是JavaScript中使用最为广泛的继承策略。

// 父类
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

// 子类
class Student extends Person {
  constructor(name, age, major) {
    super(name, age);
    this.major = major;
  }

  study() {
    console.log(`I am studying ${this.major}.`);
  }
}

const student = new Student('Alice', 20, 'Computer Science');
student.greet(); // Hello, my name is Alice and I am 20 years old.
student.study(); // I am studying Computer Science.

组合继承

组合继承将原型链继承和经典继承结合起来,既继承了父对象的原型,也继承了父对象的实例属性和方法。这种继承策略能够解决经典继承中无法直接访问父对象实例属性和方法的问题。

// 父类
const Person = {
  name: 'John',
  age: 30,
  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

// 子类
function Student(name, age, major) {
  // 原型链继承
  this.__proto__ = Person;

  // 经典继承
  Person.call(this, name, age);

  this.major = major;
}

Student.prototype.study = function() {
  console.log(`I am studying ${this.major}.`);
};

const student = new Student('Alice', 20, 'Computer Science');
student.greet(); // Hello, my name is Alice and I am 20 years old.
student.study(); // I am studying Computer Science.

原型式继承

原型式继承使用一个现有的对象作为原型来创建新对象。新对象与原型对象共享相同的属性和方法。这种继承策略简单易用,但不能实现多重继承。

// 父对象
const Person = {
  name: 'John',
  age: 30,
  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

// 子对象
const student = Object.create(Person);
student.name = 'Alice';
student.age = 20;
student.greet(); // Hello, my name is Alice and I am 20 years old.

寄生式继承

寄生式继承将父对象的属性和方法拷贝到子对象中,但子对象与父对象没有原型链关系。这种继承策略可以实现多重继承,但会增加对象的内存占用。

// 父对象
const Person = {
  name: 'John',
  age: 30,
  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

// 子对象
function Student(name, age, major) {
  // 拷贝父对象的属性和方法到子对象
  for (let key in Person) {
    this[key] = Person[key];
  }

  this.name = name;
  this.age = age;
  this.major = major;
}

Student.prototype.study = function() {
  console.log(`I am studying ${this.major}.`);
};

const student = new Student('Alice', 20, 'Computer Science');
student.greet(); // Hello, my name is Alice and I am 20 years old.
student.study(); // I am studying Computer Science.

寄生组合式继承

寄生组合式继承将寄生式继承和组合继承结合起来,既实现了多重继承,又解决了寄生式继承中增加内存占用