返回

ES5中类的继承有多种姿势?

前端

前言

在JavaScript中,类继承是一个非常重要的概念,它允许我们创建出新的类,这些新类可以继承自其他类,并获得其属性和方法。在ES6中,类继承可以使用extends语法糖轻松实现,但是在ES5中,类继承需要通过操作对象原型链来实现,这可能会让一些初学者感到困惑。

本文将详细介绍ES5中类的继承实现方式,包括原型链继承、构造函数继承和组合继承。通过本文,您将能够轻松掌握ES5中的类继承技巧,并将其应用到您的JavaScript开发实践中。

原型链继承

原型链继承是ES5中最基本、最简单的类继承方式。它的基本原理是:每个对象都有一个原型对象,原型对象也是一个对象,它拥有自己的属性和方法。当一个对象找不到自己属性或方法时,它会沿着原型链向上查找,直到找到该属性或方法为止。

实现原理

原型链继承的实现原理非常简单,只需要通过设置对象的原型对象即可。例如:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

function Student(name, age, school) {
  Person.call(this, name, age);
  this.school = school;
}

Student.prototype = Object.create(Person.prototype);

const student = new Student('John Doe', 20, 'Harvard University');
student.sayHello(); // Hello, my name is John Doe and I am 20 years old.

在上面的代码中,我们首先定义了Person类,该类具有nameage两个属性,以及sayHello方法。然后,我们定义了Student类,该类继承自Person类。在Student类中,我们通过Person.call(this, name, age);来调用Person类的构造函数,并通过Object.create(Person.prototype);来设置Student类的原型对象为Person类的原型对象。这样,Student类就继承了Person类的属性和方法。

优缺点

原型链继承的优点是简单易懂,实现方便。它的缺点是:

  • 无法继承构造函数中的属性和方法。
  • 无法重写父类的方法。
  • 子类无法访问父类的私有属性和方法。

构造函数继承

构造函数继承是ES5中另一种常见的类继承方式。它的基本原理是:子类的构造函数调用父类的构造函数,然后子类再向自己的原型对象中添加属性和方法。

实现原理

构造函数继承的实现原理如下:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

function Student(name, age, school) {
  Person.call(this, name, age);
  this.school = school;
}

Student.prototype = new Person();

const student = new Student('John Doe', 20, 'Harvard University');
student.sayHello(); // Hello, my name is John Doe and I am 20 years old.

在上面的代码中,我们首先定义了Person类,该类具有nameage两个属性,以及sayHello方法。然后,我们定义了Student类,该类继承自Person类。在Student类的构造函数中,我们通过Person.call(this, name, age);来调用Person类的构造函数,并通过new Person();来创建一个新的Person对象,并将该对象赋值给Student类的原型对象。这样,Student类就继承了Person类的属性和方法。

优缺点

构造函数继承的优点是:

  • 可以继承构造函数中的属性和方法。
  • 可以重写父类的方法。
  • 子类可以访问父类的私有属性和方法。

构造函数继承的缺点是:

  • 代码冗余,因为子类的构造函数中需要重复父类的构造函数代码。
  • 难以管理,因为子类的原型对象指向父类的一个实例,这使得子类难以扩展。

组合继承

组合继承是ES5中最为复杂的类继承方式。它的基本原理是:子类的构造函数同时调用父类的构造函数和原型对象的构造函数,然后子类再向自己的原型对象中添加属性和方法。

实现原理

组合继承的实现原理如下:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

function Student(name, age, school) {
  Person.call(this, name, age);
  Student.prototype.constructor.call(this, name, age, school);
}

Student.prototype = Object.create(Person.prototype);

const student = new Student('John Doe', 20, 'Harvard University');
student.sayHello(); // Hello, my name is John Doe and I am 20 years old.

在上面的代码中,我们首先定义了Person类,该类具有nameage两个属性,以及sayHello方法。然后,我们定义了Student类,该类继承自Person类。在Student类的构造函数中,我们通过Person.call(this, name, age);来调用Person类的构造函数,并通过Student.prototype.constructor.call(this, name, age, school);来调用Student类的原型对象的构造函数。这样,Student类就继承了Person类的属性和方法。

优缺点

组合继承的优点是:

  • 同时具有原型链继承和构造函数继承的优点。
  • 可以避免代码冗余。
  • 可以更轻松地管理子类。

组合继承的缺点是:

  • 代码相对复杂,不易理解。
  • 性能开销较大,因为需要调用两次构造函数。

总结

本文详细介绍了ES5中类的继承实现方式,包括原型链继承、构造函数继承和组合继承。每种继承方式都有其优缺点,开发者可以根据自己的需求选择合适的继承方式。

在实际开发中,最常用的类继承方式是组合继承,因为它综合了原型链继承和构造函数继承的优点,同时避免了它们的缺点。但是,组合继承的代码相对复杂,不易理解,因此不适合初学者使用。

对于初学者来说,原型链继承是一种比较简单易懂的类继承方式,因此推荐初学者使用原型链继承。当开发者熟悉了原型链继承之后,再学习构造函数继承和组合继承。