返回

JavaScript 继承详解

前端

面向对象编程和继承

面向对象编程(OOP)是一种软件开发范式,它将数据和行为封装在对象中,并通过对象之间的交互来实现程序的功能。继承是 OOP 中的重要概念之一,它允许新对象从现有对象(父对象)继承属性和方法,从而实现代码的重用和维护。

JavaScript 中的继承

JavaScript 是一种面向对象语言,但它与 Java、C++ 等传统面向对象语言的继承机制有很大不同。JavaScript 采用原型链(prototype chain)来实现继承,而不是类(class)和实例(instance)的概念。

原型链

在 JavaScript 中,每个对象都有一个原型对象(prototype object),原型对象包含了该对象所有属性和方法的定义。当一个对象访问一个不存在的属性或方法时,JavaScript 会自动沿着原型链向上查找,直到找到该属性或方法的定义为止。

构造函数

JavaScript 中的构造函数(constructor function)用于创建新对象。构造函数的名称通常以大写字母开头,例如:

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

当调用构造函数时,JavaScript 会创建一个新的对象,并将构造函数中的参数作为该对象的属性。例如:

const person1 = new Person('John', 30);

person1 对象的原型对象就是 Person.prototype 对象,它包含了 Person 构造函数中定义的所有属性和方法。

原型对象

原型对象(prototype object)是构造函数的属性,它包含了该构造函数创建的所有对象的共有属性和方法。例如:

Person.prototype.sayHello = function() {
  console.log('Hello, my name is ' + this.name);
};

Person.prototype.sayHello 方法可以被所有 Person 构造函数创建的对象使用。例如:

person1.sayHello(); // Hello, my name is John

JavaScript 继承的实现

JavaScript 中的继承可以通过以下步骤实现:

  1. 定义父对象(父类)的构造函数。
  2. 定义子对象(子类)的构造函数,并将父对象的构造函数作为子对象的原型对象。
  3. 在子对象的原型对象中定义子对象独有的属性和方法。

例如:

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

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

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

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

const student1 = new Student('John', 20, 'Computer Science');

student1.sayHello(); // Hello, my name is John
student1.study(); // I am studying Computer Science

在上面的示例中,Person 构造函数是父对象,Student 构造函数是子对象。Student 构造函数的原型对象是 Person.prototype 对象,Student.prototype 对象中定义了子对象独有的属性和方法。

JavaScript 继承的局限性

JavaScript 中的原型链继承机制虽然简单易用,但它也存在一些局限性:

  • 继承是单向的。 子对象只能继承父对象,而父对象无法继承子对象。
  • 父对象的变化会影响子对象。 如果修改了父对象的原型对象,那么所有子对象的原型对象也会被修改。
  • 子对象无法访问父对象的私有属性和方法。 在 JavaScript 中,私有属性和方法只能在对象内部访问,子对象无法访问父对象的私有属性和方法。

ES6 中的继承

ES6 引入了 class 和 extends ,使得 JavaScript 的继承机制更加现代化。class 和 extends 关键字的使用方式与 Java、C++ 等语言中的 class 和 extends 关键字类似。

例如:

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

  sayHello() {
    console.log('Hello, my name is ' + this.name);
  }
}

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

  study() {
    console.log('I am studying ' + this.major);
  }
}

const student1 = new Student('John', 20, 'Computer Science');

student1.sayHello(); // Hello, my name is John
student1.study(); // I am studying Computer Science

在上面的示例中,Person 类是父类,Student 类是子类。Student 类继承了 Person 类的所有属性和方法,并添加了新的属性和方法。

总结

JavaScript 中的继承机制非常灵活,它允许开发人员根据需要实现不同的继承方式。JavaScript 继承的局限性可以通过 ES6 中的 class 和 extends 关键字来弥补。通过理解 JavaScript 中的继承机制,开发人员可以编写出更加清晰、可维护的代码。