返回

剖析 JavaScript 继承的六种方式:全方位理解与应用

前端

六种方式详解 JS 继承:深入浅出,一学即懂

引言

JavaScript 继承是面向对象编程 (OOP) 的一项基石,它使我们可以创建新对象,这些对象具有从现有对象继承属性和方法的能力。本文将详细介绍 JavaScript 继承的六种主要方式,从基本概念到高级技术,逐步深入浅出地剖析它们的原理和用法。

1. 原型继承

原型继承是 JavaScript 中最基本、最直接的继承方式。它利用了 JavaScript 的原型链机制。每个 JavaScript 对象都有一个称为 __proto__ 的内部属性,该属性指向其构造函数的原型对象。通过修改构造函数的原型,我们可以为所有由该构造函数创建的对象添加属性和方法。

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

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person1 = new Person('John');
person1.greet(); // 输出: Hello, my name is John.

2. 构造函数继承

构造函数继承通过显式调用父构造函数来实现继承。子构造函数首先调用父构造函数,然后在其自身的方法中添加额外的属性和方法。这是一种相当简单明了的方法,但它存在一些缺点,比如难以共享方法和无法继承父类的原型属性。

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

Parent.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

Child.prototype.getAge = function() {
  return this.age;
};

const child1 = new Child('Jane', 25);
child1.greet(); // 输出: Hello, my name is Jane.
child1.getAge(); // 输出: 25

3. 组合继承

组合继承将原型继承和构造函数继承相结合。它首先使用原型继承来建立子类的原型链,然后使用构造函数继承来初始化子类的实例属性。这种方法继承了父类的原型方法,同时还允许子类定义自己的实例属性和方法。

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

Parent.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

function Child(name, age) {
  Parent.prototype.constructor.apply(this, arguments);
  this.age = age;
}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

const child1 = new Child('Bob', 30);
child1.greet(); // 输出: Hello, my name is Bob.
child1.getAge(); // 输出: 30

4. 借用构造函数

借用构造函数是一种巧妙的技术,它允许子类访问父类的构造函数,而无需显式调用它。这通过在子构造函数中使用 new 运算符来实现,并将其指向父构造函数。这种方法避免了重复父构造函数的初始化代码,同时仍然允许子类定义自己的实例属性和方法。

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

Parent.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

function Child(name, age) {
  new Parent(name);
  this.age = age;
}

Child.prototype.getAge = function() {
  return this.age;
};

const child1 = new Child('Mary', 28);
child1.greet(); // 输出: Hello, my name is Mary.
child1.getAge(); // 输出: 28

5. 原型式继承

原型式继承通过创建一个新对象,将其原型设置为父对象的副本来实现继承。这是一种类似于原型继承的方法,但它不涉及构造函数。它更常用于函数式编程范例中,其中对象被视为不可变的数据结构。

const parentObject = {
  name: 'Parent',
  greet: function() {
    console.log(`Hello, my name is ${this.name}.`);
  }
};

const childObject = Object.create(parentObject);
childObject.name = 'Child';
childObject.getAge = function() {
  return this.age;
};

childObject.greet(); // 输出: Hello, my name is Child.
childObject.getAge(); // 输出: undefined

6. 类式继承(ES6)

ES6 引入了 class ,它提供了类式继承的语法糖。类式继承类似于组合继承,它使用原型继承建立子类的原型链,同时使用构造函数初始化子类的实例属性。与其他继承方式相比,类式继承具有更简洁、更直观的语法。

class Parent {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name);
    this.age = age;
  }

  getAge() {
    return this.age;
  }
}

const child1 = new Child('Tom', 32);
child1.greet(); // 输出: Hello, my name is Tom.
child1.getAge(); // 输出: 32

结论

JavaScript 继承提供了多种机制来创建新对象,这些对象继承了现有对象的属性和方法。通过理解这些不同方式的原理和权衡利弊,开发者可以根据具体需求选择最合适的继承方法。从基本原理到高级技术,本文对 JavaScript 继承进行了全面而深入浅出的讲解,旨在帮助初学者和经验丰富的开发者提高他们的技能。