Heim >Web-Frontend >js-Tutorial >Eine Einführung in die Methode zur Implementierung der Vererbung in JavaScript-Prototypen

Eine Einführung in die Methode zur Implementierung der Vererbung in JavaScript-Prototypen

青灯夜游
青灯夜游nach vorne
2020-11-19 18:10:303582Durchsuche

Eine Einführung in die Methode zur Implementierung der Vererbung in JavaScript-Prototypen

In diesem Artikel besprechen wir Prototypen und wie man sie für die Vererbung in JS verwendet. Wir werden auch sehen, wie sich Prototypmethoden von der klassenbasierten Vererbung unterscheiden.

Vererbung

Vererbung ist ein charakteristisches Merkmal von Programmiersprachen, das mit der Einführung objektorientierter Programmiersprachen entstand. Die meisten dieser Sprachen sind klassenbasierte Sprachen. Hier ist die Klasse wie eine Blaupause und das Objekt ist ihre Darstellung. Das heißt, um ein Objekt zu erstellen, müssen wir zuerst eine Klasse erstellen und dann können wir eine beliebige Anzahl von Objekten aus einer Klasse erstellen.

Stellen Sie sich vor, wir haben eine Klasse, die ein Smartphone darstellt. Diese Klasse verfügt wie andere Smartphones über Funktionen wie das Aufnehmen von Bildern und die GPS-Positionierung. Das Folgende ist eine Beschreibung einer solchen Klasse mit C++:

class SmartPhone {
  public:
  void captureImages() {}
}

SmartPhone x;
x.captureImages()

Wir haben eine Klasse namens SmartPhone erstellt, die über eine Methode namens capturePictures zum Aufnehmen von Bildern verfügt. SmartPhone的类,它有一个名为capturePictures的方法用来拍照。

如果我们需要一个iPhone类,它可以捕捉图像和一些特殊的功能,比如面部ID扫描。下面是两种可能的解决方案:

  • 将捕获图像功能与其他常见的智能手机功能,以及iPhone的特定功能一起重写到一个新类中。但是这种方法需要更多的时间和精力,并且会引入更多的bug。

  • 重用SmartPhone类中的功能,这就是继承的作用,继承也是重用其他类/对象中功能的一种方式。

这里是我们如何从SmartPhone类中继承capturePictures方法,使用 c++ 实现如下:

class Iphone: public SmartPhone {
  public:
  void faceIDScan() {}
}

Iphone x

x.faceIDScan()

x.captureImages()

上面是一个简单的继承示例。 但是,它表明继承可以使我们以某种方式重用代码,从而使所生成的程序更不易出错,并且花费更少的时间进行开发。

以下是关于类的一些重要信息:

  • 继承该功能的类称为子类
  • 被继承的类称为父类
  • 一个类可以同时从多个类中继承
  • 我们可以具有多个继承级别。 例如,类C继承自类B,而类B继承自类A

值得注意的是,类本身并没有做任何事情。在从类创建对象之前,实际上没有完成任何工作。我们将看到它为什么不同于JavaScript。

原型是什么?

在 JS 中,所有对象都有一个特殊的内部属性,该属性基本上是对另一个对象的引用。 此引用取决于对象的创建方式。 在 ECMAScript/JavaScript规范中,它表示为[[Prototype]]

由于[[Prototype]]链接到一个对象,所以该对象有自己的[[Prototype]]引用。这就是建立原型链的方式。

这个[[Prototype]]链是 JS 中继承的构建块。

__proto__ 对象

为了访问对象的[[Prototype]],大多数浏览器都提供__proto__属性。访问方式如下:

obj.__proto__

需要注意的是,这个属性不是 ECMAScript 标准的一部分,它实际上是由浏览器实现的。

获取和设置原型方法

除了__proto__属性外,还有一种访问[[Prototype]]的标准方法:

Object.getPrototypeOf(obj);

对应的有个类似的方法来设置对象的[[Prototype]]

Object.setPrototypeOf(obj, prototype);

[[Prototype]].prototype属性

[[Prototype]] 只不过是一种用来表示物体原型的标准符号。 许多开发人员将其与.prototype属性混淆,这是完全不同的事情,接着我们来研究一下.prototype属性。

在 JS 中,有许多创建对象的方法。一种方法是使用构造函数,像这样使用new关键字来调用它:

function SmartPhone(os) {
  this.os = os
}

let phone = new SmartPhone('Android')

在控制台打印 phone 对象:

{
  os: "IPhone"
  __proto__{
    constructor: ƒ SmartPhone(os)
   __proto__: Object
  }
}

现在,如果我们希望在phone对象上有一些方法,我们可以在函数上使用.prototype属性,如下所示:

SmartPhone.prototype.isAndroid = function () {
  return this.os === 'Android' || 'android'
}

再次创建phone对象时,打印 phone 对象如下:

{
  os: "Android"
  __proto__{
    isAndroid: ƒ()
    constructor: ƒ SmartPhone(os)
   __proto__: Object
  }
}

我们可以在对象的[[Prototype]]中看到isAndroid()方法。

简而言之,.prototype属性基本上就像由给定的构造函数创建的[[Prototype]]对象的蓝图。 在.prototype属性/对象中声明的所有内容都会在对象的[[Prototype]]中弹出。

实上,如果将 SmartPhone.prototype 与phone 的[[Prototype]]

Wenn wir eine iPhone-Klasse benötigen, die Bilder und einige spezielle Funktionen wie das Scannen von Gesichts-IDs erfassen kann. Hier sind zwei mögliche Lösungen:

  • Schreiben Sie die Funktion „Bild erfassen“ in eine neue Klasse um. Dieser Ansatz erfordert jedoch mehr Zeit und Mühe und führt zu mehr Fehlern. 🎜
  • Funktionen in der Klasse SmartPhone wiederverwenden. Dies ist die Rolle der Vererbung, die auch eine Möglichkeit darstellt, Funktionen in anderen Klassen/Objekten wiederzuverwenden.
🎜So erben wir die Methode capturePictures von der Klasse SmartPhone, indem wir C++ wie folgt verwenden: 🎜
console.log(Object.getPrototypeOf(phone) === SmartPhone.prototype);
// true
🎜Das Obige ist eine einfache Vererbung Beispiel . Es zeigt jedoch, dass die Vererbung es uns ermöglicht, Code auf eine Weise wiederzuverwenden, die das resultierende Programm weniger fehleranfällig macht und weniger Zeit für die Entwicklung benötigt. 🎜🎜Hier einige wichtige Informationen zu Klassen: 🎜
  • Die Klasse, die die Funktionalität erbt, wird als Unterklasse bezeichnet
  • Die Klasse, die geerbt wird, wird als übergeordnete Klasse bezeichnet
  • A Eine Klasse kann von mehreren Klassen gleichzeitig erben.
  • Wir können mehrere Vererbungsebenen haben. Beispielsweise erbt Klasse C von Klasse B und Klasse B von Klasse A
🎜Es ist erwähnenswert, dass die Klasse selbst nichts tut. Es wird eigentlich keine Arbeit geleistet, bis das Objekt aus der Klasse erstellt wird. Wir werden sehen, warum es sich von JavaScript unterscheidet. 🎜🎜Was ist ein Prototyp? 🎜🎜In JS haben alle Objekte eine spezielle interne Eigenschaft, die im Grunde eine Referenz auf ein anderes Objekt ist. Diese Referenz hängt davon ab, wie das Objekt erstellt wurde. In der ECMAScript/JavaScript-Spezifikation wird es als [[Prototype]] dargestellt. 🎜🎜Da [[Prototype]] mit einem Objekt verknüpft ist, verfügt das Objekt über eine eigene [[Prototype]]-Referenz. So bauen Sie eine Prototypenkette auf. 🎜🎜Diese [[Prototype]]-Kette ist der Baustein der Vererbung in JS. 🎜🎜__proto__ Objekt 🎜🎜Um auf den [[Prototype]] des Objekts zuzugreifen, stellen die meisten Browser das Attribut __proto__ bereit. Der Zugriff erfolgt wie folgt: 🎜
function ObjectA() {
  this.methodA = function () {}
}

let firstObj = new ObjectA()
console.log(firstObj)
🎜Beachten Sie, dass diese Eigenschaft nicht Teil des ECMAScript-Standards ist und tatsächlich von Browsern implementiert wird. 🎜🎜Prototypmethoden abrufen und festlegen🎜🎜Zusätzlich zum Attribut __proto__ gibt es auch eine Standardmethode für den Zugriff auf [[Prototype]]: 🎜
function MyObject() {}
MyObject.prototype.propA = 10; // 在原型上创建属性

let myObject = new MyObject();
console.log(myObject.propA); // [[Prototype]]上的属性
// 10

myObject.propA = 20; // 对象的属性
console.log(myObject.propA);
// 20
🎜Es gibt eine Ähnliche Methoden zum Festlegen der [[Prototype]]-Eigenschaften des Objekts: 🎜
let obj = {}
🎜[[Prototype]] und .prototype-Eigenschaften 🎜🎜[ [Prototyp]] ist nichts anderes als ein Standardsymbol, das zur Darstellung des Prototyps eines Objekts verwendet wird. Viele Entwickler verwechseln es mit dem Attribut .prototype, was etwas völlig anderes ist. Werfen wir einen Blick auf das Attribut .prototype. 🎜🎜In JS gibt es viele Möglichkeiten, Objekte zu erstellen. Eine Möglichkeit besteht darin, den Konstruktor zu verwenden und ihn mit dem Schlüsselwort new wie folgt aufzurufen: 🎜
let obj = new Object();
🎜 Drucken Sie das phone-Objekt in der Konsole aus: 🎜
let SmartPhone = {
  captureImages: function() {}
}

let Iphone = Object.create(SmartPhone)

Iphone.captureImages()
🎜Jetzt, wenn wir möchten Es gibt einige Methoden für das Objekt phone und wir können das Attribut .prototype wie folgt für die Funktion verwenden: 🎜
function SmartPhone(os) {
  this.os = os;
}

SmartPhone.prototype.isAndroid = function() {
  return this.os === 'Android';
};

SmartPhone.prototype.isIOS = function() {
  return this.os === 'iOS';
};
🎜Erstellen Sie das Objekt phone erneut Beim Drucken des phone-Objekts wie folgt: 🎜
function Iphone() {
   SmartPhone.call(this, 'iOS');
}
🎜Wir können die isAndroid()-Methode im [[Prototype]] des Objekts sehen. 🎜🎜Kurz gesagt ist die Eigenschaft .prototype im Grunde wie eine Blaupause für ein [[Prototype]]-Objekt, das von einem bestimmten Konstruktor erstellt wurde. Alles, was in einer .prototype-Eigenschaft/einem .prototype-Objekt deklariert ist, wird im [[Prototype]] des Objekts angezeigt. 🎜🎜Wenn Sie SmartPhone.prototype mit <code>[[Prototype]] von phone vergleichen, werden Sie tatsächlich feststellen, dass sie gleich sind: 🎜
Iphone.prototype = Object.create(SmartPhone.prototype);
🎜Das ist erwähnenswert , wir können auch Methoden im Konstruktor erstellen: 🎜
function ObjectA() {
  this.methodA = function () {}
}

let firstObj = new ObjectA()
console.log(firstObj)

这种方法的问题是当我们初始化一个新对象时。所有实例都有自己methodA的副本。相反,当我们在函数的原型上创建它时,对象的所有实例只共享方法的一个副本,显然使用原型的方式效率会过高。

当我们访问属性时这里发生了什么?

当我们访问一个属性以获取它时,会发生以下情况:

JS 引擎查找对象上的属性,如果找到了该属性,然后返回它。否则,JS 引擎将通过查看[[Prototype]]来检查对象的继承属性,如果找到该属性,则返回它,否则,它会查找 [[Prototype]][[Prototype]]。 找到属性或没有[[Prototype]]时,该链结束,这意味着我们已经到达原型链的末端。

当我们设置/创建属性时,JS 总是在对象本身上进行设置。 即使[[Prototype]]链上存在相同的属性,下面是一个例子:

function MyObject() {}
MyObject.prototype.propA = 10; // 在原型上创建属性

let myObject = new MyObject();
console.log(myObject.propA); // [[Prototype]]上的属性
// 10

myObject.propA = 20; // 对象的属性
console.log(myObject.propA);
// 20

在上面的示例中,我们创建了一个构造函数,该函数的[[Prototype]]上具有属性propA。 当我们尝试对其进行读取操作时,会在控制台中看到该值。 但是,当我们尝试在对象本身上设置相同的属性时;JS 使用给定值在对象上创建一个新属性。 现在,如果我们不能直接访问[[Prototype]]上的属性。

值得注意的是,普通对象的[[Prototype]]链的末尾是内置的Object.prototype。 这就是为什么大多数对象共享许多方法(例如toString())的原因。 因为它们实际上是在Object.prototype上定义的。

使用原型继承的各种方法

在 JS 中,无论我们如何创建对象,只有原型继承,但这些方式还有一些区别,来看看:

对象字面量

在JavaScript中创建对象的最简单方法是使用对象字面量:

let obj = {}

如果在浏览器的控制台中打印obj,我们将看到以下内容:

Eine Einführung in die Methode zur Implementierung der Vererbung in JavaScript-Prototypen

基本上,所有用文字面量创建的对象都继承了Object.prototype的属性。

需要注意的是__proto__对象引用了创建它的构造函数。 在这种情况下,constructor属性指向Object构造函数。

使用对象构造函数

另一种不太常见的创建对象的方法是使用对象构造函数。JS 提供了一个名为Object的内置构造函数方法来创建对象。

let obj = new Object();

这种方法的结果与对象字面量的方式相同。它从Object.prototype继承属性。因为我们使用Object作为构造函数。

Object.create 方法

使用此辅助方法,我们可以创建一个带有[[Prototype]]的对象,如下所示:

let SmartPhone = {
  captureImages: function() {}
}

let Iphone = Object.create(SmartPhone)

Iphone.captureImages()

这是在 JS 中使用继承的最简单方法之一。猜猜我们如何在没有任何[[Prototype]]引用的情况下创建对象?

构造方法

与 JS 运行时提供的对象构造函数相似。 我们还可以创建自己的构造函数,以创建适合我们需求的对象,如下所示:

function SmartPhone(os) {
  this.os = os;
}

SmartPhone.prototype.isAndroid = function() {
  return this.os === 'Android';
};

SmartPhone.prototype.isIOS = function() {
  return this.os === 'iOS';
};

现在,我们想创建一个iPhone类,它应该有'iOS'作为它 os 属性的值。它还应该有faceIDScan方法。

首先,我们必须创建一个Iphone构造函数,在其中,我们应该调用SmartPhone构造函数,如下所示:

function Iphone() {
   SmartPhone.call(this, 'iOS');
}

这会将Iphone构造函数中的this.os属性设置为’iOS‘

之所以调用SmartPhone.call方法,是因为我们需要更改 this 值以引用Iphone。 这类似于在面向对象的世界中调用父级的构造函数。

接下来的事情是,我们必须从SmartPhone构造函数继承方法。 我们可以在此处使用Object.create朋友,如下所示:

Iphone.prototype = Object.create(SmartPhone.prototype);

现在,我们可以使用.prototypeIphone添加方法,如下所示:

Iphone.prototype.faceIDScan = function() {};

最后,我们可以使用Iphone创建一个对象,如下所示:

let x = new Iphone();

// calling inherited method
console.log(x.isIOS()):
// true

ES6 class

使用ES6,整个过程非常简单。 我们可以创建类(它们与C ++或其他任何基于类的语言中的类不同,只是在原型继承之上的语法糖),然后从其他类派生新的类。

下面是我们如何在ES6中创建类:

class SmartPhone {
  constructor(os) {
    this.os = os;
  }
  isAndroid() {
    return this.os === 'Android';
  }
  isIos() {
    return this.os === 'iOS';
  }
};

现在,我们可以创建一个派生自SmartPhone的新类,如下所示:

class Iphone extends SmartPhone {
   constructor() {
     super.call('iOS');
   }
   faceIDScan() {}
}

我们不是调用SmartPhone.call,而是调用super.call。 在内部,JavaScript引擎会自动为我们执行此操作。

最后,我们可以使用Iphone创建一个对象,如下所示

let x = new Iphone();

x.faceIDScan();

// calling inherited method
console.log(x.isIos()):
// true

该ES6示例与先前的构造方法示例相同。 但是阅读和理解起来要干净得多。

原文:https://javascript.info/prototype-inheritance

作者:Indermohan Sing

更多编程相关知识,请访问:编程课程!!

Das obige ist der detaillierte Inhalt vonEine Einführung in die Methode zur Implementierung der Vererbung in JavaScript-Prototypen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen