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()
方法。
请注意,现在您应该使用的 ES6class
和extends
关键字来实现继承。因为这要简单得多。
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 使用原型继承。