myfreax

JavaScript 原型继承

在本教程中,您将了解 JavaScript 原型继承的工作原理

JavaScript 原型继承
JavaScript 原型继承

在本教程中,您将了解 JavaScript 原型继承的工作原理。

JavaScript 原型继承简介

如果您使用过其他面向对象的编程语言(如 Java 或 C++),您就会熟悉继承概念。

在这种编程范式中,类是创建对象的蓝图。如果您希望新类重用现有类的功能,您可以创建一个扩展现有类的新类。这称为经典继承

JavaScript 不使用经典继承。相反,它使用原型继承。在原型继承中,一个对象通过原型链接从另一个对象继承属性

JavaScript 原型继承和  __proto__

让我们举个例子来说明这个概念。下面定义一个 person 对象:

let person = {
    name: "John Doe",
    greet: function () {
        return "Hi, I'm " + this.name;
    }
};

在这个例子中,person 对象有一个属性和一个方法:

  • name 是存储人名的属性。
  • greet 是一种以字符串形式返回问候语的方法。

默认情况下,JavaScript 引擎为您提供一个内置 Object() 函数和一个匿名对象,可以通过以下方式引用 Object.prototype

请注意,圆圈代表一个函数,而正方形代表一个对象。

person 对象具有指向函数引用的匿名对象的链接Object()。代表[[Prototype]]联动:

这意味着 person 对象可以调用匿名对象定义的任何方法,通过匿名对象的引用 Object.prototype 。例如,下面展示如何通过 person 对象调用 toString() 方法:

console.log(person.toString());

输出:

[object Object]

[object Object] 是对象的默认字符串表示形式。

当您通过 person 调用 toString() 方法时,JavaScript 引擎无法在 person 对象找到toString() 方法。因此,JavaScript 引擎遵循原型链并在 Object.prototype 对象中搜索方法。

由于 JavaScript 引擎可以在Object.prototype对象中找到 toString() 方法,因此它会执行 toString() 方法。

要访问 person 对象的原型,可以使用 __proto__ 属性。如下

console.log(person.__proto__);

下面显示 person.__proto__Object.prototype 引用同一个对象:

console.log(person.__proto__ === Object.prototype); // true

下面定义teacher 对象并且具有 teach() 方法:

let teacher = {
    teach: function (subject) {
        return "I can teach " + subject;
    }
};

person 对象一样,teacher.__proto__ 引用 Object.prototype 。如下图所示:

如果想让 teacher 对象访问 person 对象的所有方法和属性,可以像这样设置teacher 对象的原型引用 person 对象:

teacher.__proto__ = person;
请注意,不要在生产代码中使用 __proto__ 属性。请仅将其用于演示目的。

现在,teacher 对象可以通过原型链访问 person 对象的 name 属性和 greet() 方法:

console.log(teacher.name);
console.log(teacher.greet());

输出:

John DoeHi, I'm John Doe

当你在 teacher 对象调用 greet() 方法时,JavaScript 引擎首先在 teacher 对象搜索 greet() 方法。

由于 JavaScript引擎在 teacher 对象找不到 greet() 方法,它会沿着原型链搜索person 对象方法。

因为 JavaScript 引擎可以在 person 对象找到 greet() 方法,JavaScript 引擎它会执行方法。

在 JavaScript,我们说 teacher 对象继承 person 对象的方法和属性。而这种继承称为原型继承。

在 ES5 实现原型继承的标准方法

ES5 提供一种标准方法来处理原型继承,通过使用 Object.create() 方法。

请注意,现在您应该使用的 ES6 classextends 关键字来实现继承。因为这要简单得多。

Object.create() 方法创建一个新对象并使用现有对象作为新对象的原型:

Object.create(proto, [propertiesObject])

Object.create() 方法接受两个参数:

  • 第一个参数 proto 是用作新对象原型的对象。
  • 第二个参数 propertiesObject 是一个可选对象,它为新对象定义附加属性。

假设你有一个 person 对象:

let person = {
    name: "John Doe",
    greet: function () {
        return "Hi, I'm " + this.name;
    }
};

下面创建一个空的 teacher 对象基于 person 对象的 __proto__

let teacher = Object.create(person);

之后,您可以为 teacher 对象定义属性:

teacher.name = 'Jane Doe';
teacher.teach = function (subject) {
        return "I can teach " + subject;
}

或者您可以在一个语句中执行这些步骤,如下所示:

let teacher = Object.create(person, {
    name: { value: 'John Doe' } ,
    teach: { value: function(subject) {
        return "I can teach " + subject;
    }}
});

ES5 还引入了 Object.getPrototypeOf() 返回对象原型的方法。例如:

console.log(Object.getPrototypeOf(teacher) === person);

输出:

true

结论

  • 继承允许一个对象使用另一个对象的属性和方法,而无需复制代码。
  • JavaScript 使用原型继承。

内容导航