Beide Codebeispiele, die Sie in Ihrer Frage demonstriert haben, verwenden die prototypische Vererbung. Tatsächlich ist jeder objektorientierte Code, den Sie in JavaScript schreiben, ein Paradigma der prototypischen Vererbung. JavaScript hat einfach keine klassische Vererbung. Dies sollte die Dinge ein wenig aufklären:
Inheritance
|
+-----------------------------+
| |
v v
Prototypal Classical
|
+------------------------------+
| |
v v
Prototypal Pattern Constructor Pattern
Wie Sie sehen können, sind prototypische Vererbung und klassische Vererbung zwei verschiedene Paradigmen der Vererbung. Einige Sprachen wie Self, Lua und JavaScript unterstützen die prototypische Vererbung. Die meisten Sprachen wie C ++, Java und C # unterstützen jedoch die klassische Vererbung.
Ein kurzer Überblick über die objektorientierte Programmierung
Sowohl die prototypische Vererbung als auch die klassische Vererbung sind objektorientierte Programmierparadigmen (dh sie befassen sich mit Objekten). Objekte sind einfach Abstraktionen, die die Eigenschaften einer realen Entität einschließen (dh sie repräsentieren reale Wortsachen im Programm). Dies ist als Abstraktion bekannt.
Abstraktion: Die Darstellung realer Dinge in Computerprogrammen.
Theoretisch wird eine Abstraktion definiert als "ein allgemeines Konzept, das durch Extrahieren gemeinsamer Merkmale aus bestimmten Beispielen gebildet wird". Für diese Erklärung werden wir jedoch stattdessen die oben genannte Definition verwenden.
Jetzt haben einige Objekte viele Gemeinsamkeiten. Zum Beispiel haben ein Schlammrad und eine Harley Davidson viel gemeinsam.
Ein Schlammrad:
Eine Harley Davidson:
Ein Schlammrad und eine Harley Davidson sind beide Fahrräder. Daher ist ein Fahrrad eine Verallgemeinerung sowohl eines Schlammrads als auch einer Harley Davidson.
Bike
|
+---------------------------------+
| |
v v
Mud Bike Harley Davidson
Im obigen Beispiel sind das Fahrrad, das Schlammrad und die Harley Davidson Abstraktionen. Das Fahrrad ist jedoch eine allgemeinere Abstraktion des Schlammfahrrads und der Harley Davidson (dh sowohl das Schlammfahrrad als auch die Harley Davidson sind bestimmte Arten von Fahrrädern).
Generalisierung: Eine Abstraktion einer spezifischeren Abstraktion.
In der objektorientierten Programmierung erstellen wir Objekte (die Abstraktionen realer Entitäten sind) und verwenden entweder Klassen oder Prototypen, um Verallgemeinerungen dieser Objekte zu erstellen. Verallgemeinerungen werden durch Vererbung erstellt. Ein Fahrrad ist eine Verallgemeinerung eines Schlammfahrrads. Daher erben Schlammfahrräder von Fahrrädern.
Klassische objektorientierte Programmierung
In der klassischen objektorientierten Programmierung gibt es zwei Arten von Abstraktionen: Klassen und Objekte. Ein Objekt ist, wie bereits erwähnt, eine Abstraktion einer realen Entität. Eine Klasse hingegen ist eine Abstraktion eines Objekts oder einer anderen Klasse (dh eine Verallgemeinerung). Betrachten Sie zum Beispiel:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | Man | Class of object johnDoe. |
| 3 | Human | Superclass of class Man. |
+----------------------+----------------+---------------------------------------+
Wie Sie in klassischen objektorientierten Programmiersprachen sehen können, sind Objekte nur Abstraktionen (dh alle Objekte haben eine Abstraktionsstufe von 1) und Klassen sind nur Verallgemeinerungen (dh alle Klassen haben eine Abstraktionsstufe größer als 1).
Objekte in klassischen objektorientierten Programmiersprachen können nur durch Instanziieren von Klassen erstellt werden:
class Human {
// ...
}
class Man extends Human {
// ...
}
Man johnDoe = new Man();
In klassischen objektorientierten Programmiersprachen sind Objekte Abstraktionen realer Entitäten und Klassen Verallgemeinerungen (dh Abstraktionen von Objekten oder anderen Klassen).
Daher werden Entitäten mit zunehmender Abstraktionsebene allgemeiner und mit abnehmender Abstraktionsebene Entitäten spezifischer. In diesem Sinne ist die Abstraktionsebene analog zu einer Skala, die von spezifischeren Entitäten bis zu allgemeineren Entitäten reicht.
Prototypische objektorientierte Programmierung
Prototypische objektorientierte Programmiersprachen sind viel einfacher als klassische objektorientierte Programmiersprachen, da wir in der prototypischen objektorientierten Programmierung nur einen Abstraktionstyp (dh Objekte) haben. Betrachten Sie zum Beispiel:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | man | Prototype of object johnDoe. |
| 3 | human | Prototype of object man. |
+----------------------+----------------+---------------------------------------+
Wie Sie in prototypischen objektorientierten Programmiersprachen sehen können, sind Objekte Abstraktionen von Entitäten der realen Welt (in diesem Fall werden sie einfach als Objekte bezeichnet) oder anderen Objekten (in diesem Fall werden sie als Prototypen der Objekte bezeichnet, die sie abstrahieren). Ein Prototyp ist also eine Verallgemeinerung.
Objekte in prototypischen objektorientierten Programmiersprachen können entweder ex-nihilo (dh aus dem Nichts) oder aus einem anderen Objekt (das zum Prototyp des neu erstellten Objekts wird) erstellt werden:
var human = {};
var man = Object.create(human);
var johnDoe = Object.create(man);
Meiner bescheidenen Meinung nach sind prototypische objektorientierte Programmiersprachen leistungsfähiger als klassische objektorientierte Programmiersprachen, weil:
- Es gibt nur eine Art von Abstraktion.
- Verallgemeinerungen sind einfach Objekte.
Inzwischen müssen Sie den Unterschied zwischen klassischer Vererbung und prototypischer Vererbung erkannt haben. Die klassische Vererbung ist auf Klassen beschränkt, die von anderen Klassen erben. Die prototypische Vererbung umfasst jedoch nicht nur Prototypen, die von anderen Prototypen erben, sondern auch Objekte, die von Prototypen erben.
Isomorphismus der Prototypklasse
Sie müssen bemerkt haben, dass Prototypen und Klassen sehr ähnlich sind. Das ist richtig. Sie sind. Tatsächlich sind sie sich so ähnlich, dass Sie tatsächlich Prototypen verwenden können, um Klassen zu modellieren:
function CLASS(base, body) {
if (arguments.length < 2) body = base, base = Object.prototype;
var prototype = Object.create(base, {new: {value: create}});
return body.call(prototype, base), prototype;
function create() {
var self = Object.create(prototype);
return prototype.hasOwnProperty("constructor") &&
prototype.constructor.apply(self, arguments), self;
}
}
Mit der obigen CLASS
Funktion können Sie Prototypen erstellen, die wie Klassen aussehen:
var Human = CLASS(function () {
var milliseconds = 1
, seconds = 1000 * milliseconds
, minutes = 60 * seconds
, hours = 60 * minutes
, days = 24 * hours
, years = 365.2425 * days;
this.constructor = function (name, sex, dob) {
this.name = name;
this.sex = sex;
this.dob = dob;
};
this.age = function () {
return Math.floor((new Date - this.dob) / years);
};
});
var Man = CLASS(Human, function (Human) {
this.constructor = function (name, dob) {
Human.constructor.call(this, name, "male", dob);
if (this.age() < 18) throw new Error(name + " is a boy, not a man!");
};
});
var johnDoe = Man.new("John Doe", new Date(1970, 0, 1));
Das Gegenteil ist jedoch nicht der Fall (dh Sie können keine Klassen zum Modellieren von Prototypen verwenden). Dies liegt daran, dass Prototypen Objekte sind, Klassen jedoch keine Objekte. Sie sind eine ganz andere Art der Abstraktion.
Fazit
Zusammenfassend haben wir gelernt, dass eine Abstraktion ein "allgemeines Konzept ist, das durch Extrahieren gemeinsamer Merkmale aus bestimmten Beispielen gebildet wird", und dass die Verallgemeinerung "eine Abstraktion einer spezifischeren Abstraktion" ist . Wir haben auch die Unterschiede zwischen prototypischer und klassischer Vererbung kennengelernt und erfahren, wie beide zwei Gesichter derselben Medaille sind.
Zum Abschied möchte ich bemerken, dass es zwei Muster der prototypischen Vererbung gibt: das prototypische Muster und das Konstruktormuster. Das prototypische Muster ist das kanonische Muster der prototypischen Vererbung, während das Konstruktormuster verwendet wird, um die prototypische Vererbung eher wie die klassische Vererbung aussehen zu lassen. Persönlich bevorzuge ich das prototypische Muster.
PS Ich bin der Typ, der den Blog-Beitrag " Why Prototypal Inheritance Matters " geschrieben und die Frage " Vorteile der prototypischen Vererbung gegenüber der klassischen? " Beantwortet hat . Meine Antwort ist die akzeptierte Antwort.