Heim > Artikel > Web-Frontend > Detaillierte Erläuterung des Funktionsprinzips und Beispiele für prototypische Javascript-Vererbung_Javascript-Fähigkeiten
Zuerst werde ich Ihnen als Referenz ein Beispiel für die prototypische Vererbung von JS mitteilen. Der spezifische Inhalt ist wie folgt
1. JS-Prototypvererbung
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JS原型继承</title> </head> <body> <!--原型继承--> <script type="text/javascript"> //clone()函数用来创建新的类Person对象 var clone = function(obj) { var _f = function() {}; //这句是原型式继承最核心的地方,函数的原型对象为对象字面量 _f.prototype = obj; return new _f; } //先声明一个对象字面量 var Animal = { somthing: 'apple', eat: function() { console.log("eat " + this.somthing); } } //不需要定义一个Person的子类,只要执行一次克隆即可 var Cat = clone(Animal); //可以直接获得Person提供的默认值,也可以添加或者修改属性和方法 console.log(Cat.eat()); Cat.somthing = 'orange'; console.log(Cat.eat()); //声明子类,执行一次克隆即可 var Someone = clone(Cat); </script> </body> </html>
2. Wie die prototypische Vererbung von JavaScript funktioniert
Es ist bekannt, dass JavaScript die prototypische Vererbung verwendet, aber da es standardmäßig nur eine Implementierungsinstanz bereitstellt, nämlich den neuen Operator, ist die Erklärung immer verwirrend. Was sollte ich als nächstes erklären und wie man es genau verwendet? es in JavaScript.
Definition der prototypischen Vererbung
Wenn Sie die Erklärung zur prototypischen Vererbung von JS lesen, werden Sie häufig den folgenden Text sehen:
Bei der Suche nach einer Eigenschaft eines Objekts durchläuft JavaScript die Prototypenkette, bis es eine Eigenschaft mit einem bestimmten Namen findet. ——Von JavaScript Secret Garden
Die meisten Implementierungen von JavaScript verwenden das Attribut __proto__, um die Prototypenkette eines Objekts darzustellen. In diesem Artikel werden wir sehen, was der Unterschied zwischen __proto__ und Prototyp ist.
Hinweis: __proto__ ist eine informelle Verwendung, die nicht in Ihrem Code vorkommen sollte. Sie wird hier nur verwendet, um zu erklären, wie die prototypische Vererbung von JavaScript funktioniert.
Der folgende Code zeigt, wie die JS-Engine nach Attributen sucht:
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop] else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop) else return undefined }
Nehmen wir ein allgemeines Beispiel: Ein zweidimensionaler Punkt mit zweidimensionalen Koordinaten x y hat auch eine Druckmethode.
Unter Verwendung der zuvor erwähnten Definition der prototypischen Vererbung erstellen wir einen Objektpunkt mit drei Eigenschaften: x, y und print. Um einen neuen zweidimensionalen Punkt zu erstellen, müssen wir ein neues Objekt erstellen und dessen __proto__-Attribut auf Point:
zeigen lassenvar Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = {x: 10, y: 20, __proto__: Point}; p.print(); // 10 20
Die seltsame prototypische Vererbung von JavaScript
Das Verwirrende ist, dass jeder, der prototypische Vererbung lehrt, keinen solchen Code, sondern den folgenden Code gibt:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); p.print(); // 10 20
Das ist anders als versprochen. Hier wird Point zu einer Funktion, und dann gibt es eine Prototyp-Eigenschaft und einen neuen Operator. Was ist mit diesem Kerl los?
So funktioniert der neue Operator
Der Schöpfer Brendan Eich wollte, dass JS traditionellen objektorientierten Programmiersprachen wie Java und C++ ähnelt. In diesen Sprachen verwenden wir den new-Operator, um ein neues Objekt für eine Klasse zu instanziieren. Also schrieb er einen neuen Operator in JS.
C++ verfügt über das Konzept eines Konstruktors, der zum Initialisieren von Instanzeigenschaften verwendet wird, sodass der neue Operator auf Funktionen abzielen muss.
Wir müssen die Methoden des Objekts an einem Ort unterbringen, und da wir eine Prototypsprache verwenden, platzieren wir sie im Prototypattribut der Funktion.
Der neue Operator akzeptiert eine Funktion F und ihre Argumente: new F(arguments...). Dieser Vorgang ist in drei Schritte unterteilt:
Erstellen Sie eine Instanz der Klasse. In diesem Schritt wird das __proto__-Attribut eines leeren Objekts auf F.prototype gesetzt.
Initialisieren Sie die Instanz. Funktion F wird mit übergebenen Argumenten aufgerufen und das Schlüsselwort this wird auf die Instanz gesetzt.
Instanz zurückgeben.
Da wir nun wissen, wie New funktioniert, können wir es mit JS-Code implementieren:
function New (f) { var n = { '__proto__': f.prototype }; /*第一步*/ return function () { f.apply(n, arguments); /*第二步*/ return n; /*第三步*/ }; }
Ein kleines Beispiel, um seinen Arbeitsstatus zu betrachten:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p1 = new Point(10, 20); p1.print(); // 10 20 console.log(p1 instanceof Point); // true var p2 = New (Point)(10, 20); p2.print(); // 10 20 console.log(p2 instanceof Point); // true
Echte prototypische Vererbung in JavaScript
Die ECMA-Spezifikation von JS erlaubt uns nur die Verwendung des neuen Operators für die prototypische Vererbung. Aber der große Meister Douglas Crockford entdeckte einen Weg, Neues zu nutzen, um eine echte prototypische Vererbung zu erreichen! Er hat die Object.create-Funktion wie folgt geschrieben:
Object.create = function (parent) { function F() {} F.prototype = parent; return new F(); };
Das sieht seltsam aus, ist aber ziemlich nett: Es erstellt ein neues Objekt und setzt seinen Prototyp auf den gewünschten Wert. Wenn wir die Verwendung von __proto__ zulassen, können wir auch so schreiben:
Object.create = function (parent) { return { '__proto__': parent }; };
Der folgende Code ermöglicht es unserem Point, eine echte prototypische Vererbung zu übernehmen:
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = Object.create(Point); p.x = 10; p.y = 20; p.print(); // 10 20
Fazit
Wir haben gelernt, was JS-Prototypvererbung ist und wie JS sie auf bestimmte Weise implementiert. Die Verwendung echter prototypischer Vererbung (wie Object.create und __proto__) hat jedoch immer noch die folgenden Nachteile:
Schlechte Standardisierung: __proto__ ist keine Standardverwendung oder sogar eine veraltete Verwendung. Gleichzeitig unterscheiden sich auch das ursprüngliche Object.create und die von Dao Ye geschriebene Originalversion.
Schlechte Optimierung: Unabhängig davon, ob es sich um natives oder angepasstes Object.create handelt, ist seine Leistung weitaus weniger optimiert als die neue, und ersteres ist bis zu zehnmal langsamer als letzteres.
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er wird für das Studium aller hilfreich sein.