Verwendung der prototypischen Programmierung in JavaScript

15

Ich habe viel Zeit damit verbracht, einfache Widgets für Projekte wie folgt zu entwickeln:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

Aber ich habe begonnen, mein Format folgendermaßen zu ändern:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

Zugegeben, das sind dumme Beispiele, also lasst euch nicht um die Achse wickeln. Aber was ist der funktionale Unterschied und wann soll ich den einen oder anderen auswählen?

JDillon522
quelle
Ich denke, Ihr erstes Codebeispiel wird nicht funktionieren, da das Projekt den Geltungsbereich nicht verlässt. Um die Vererbung in JS zu verwenden, verwenden Sie Prototyping. Das erste Beispiel soll das Projekt nicht erweitern, daher ist die Wiederverwendbarkeit möglicherweise eingeschränkt.
Aitch
Ja, ich habe die projectDeklaration versehentlich in die Funktion eingefügt. Aktualisiert.
JDillon522,
hier gilt das gleiche. Das erste Beispiel ist statisch, das zweite ist objektorientiert.
Aitch,
1
Wenn Sie nur EINE Instanz eines Objekts verwenden, gibt es keinen Grund, eine prototypische Definition zu verwenden. Und was Sie anscheinend brauchen - ist ein Modulformat - dafür gibt es viele Optionen, siehe: addyosmani.com/writing-modular-js
c69
1
Erste für Singleton-Muster Die zweite für Nicht-Singleton (wenn 1 Klasse viele Objekte haben kann)
Kokizzu

Antworten:

6

Der erste Unterschied kann wie folgt zusammengefasst werden: thisBezieht sich auf die Instanz der Klasse. prototypebezieht sich auf Definition .

Nehmen wir an, wir haben folgende Klasse:

var Flight = function ( number ) { this.number = number; };

Hier hängen wir also this.numberan jeder Instanz der Klasse, und es ist sinnvoll, weil jede Flightihre eigene Flugnummer haben sollte.

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

Im Gegensatz dazu prototypedefiniert eine einzige Eigenschaft , die durch alle Instanzen zugegriffen werden kann.

Wenn wir nun die Flugnummer erhalten möchten, können wir einfach das folgende Snippet schreiben und alle unsere Instanzen erhalten eine Referenz auf dieses neu erstellte Objekt.

Flight.prototype.getNumber = function () { return this.number; };

Der zweite Unterschied betrifft die Art und Weise, wie JavaScript nach einer Eigenschaft eines Objekts sucht. Wenn Sie suchen , Object.whatevergeht JavaScript den ganzen Weg bis zum Hauptobjekt Objekt (das Objekt , dass alles andere aus geerbt hat), und sobald sie eine Übereinstimmung findet , wird es zurückgeben oder es nennen.

Dies geschieht jedoch nur für die prototypisierten Eigenschaften. Wenn Sie also eine höhere Ebene haben this.whatever, wird JavaScript diese nicht als Übereinstimmung betrachten und die Suche fortsetzen.

Mal sehen, wie es in der Realität passiert.

Beachten Sie zunächst, dass [fast] alles Objekte in JavaScript sind. Versuche dies:

typeof null

Nun wollen wir sehen , was in einem ist Object( man beachte die Groß- Ound .am Ende). In den Entwicklertools von Google Chrome erhalten .Sie beim Aufrufen von eine Liste der verfügbaren Eigenschaften in diesem bestimmten Objekt.

Object.

Tun Sie jetzt dasselbe für Function:

Function.

Möglicherweise bemerken Sie die nameMethode. Geht einfach und macht es an und lasst uns sehen, was passiert:

Object.name
Function.name

Nun erstellen wir eine Funktion:

var myFunc = function () {};

Und mal sehen, ob wir die nameMethode auch hier haben:

myFunc.name

Sie sollten eine leere Zeichenfolge erhalten, aber das ist in Ordnung. Sie sollten keinen Fehler oder eine Ausnahme erhalten.

Jetzt wollen Objectwir etwas zu diesem gottähnlichen hinzufügen und sehen, ob wir es auch an anderen Orten bekommen?

Object.prototype.test = "Okay!";

Und los geht's:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

In allen Fällen sollten Sie sehen "Okay!".

In Bezug auf die Vor- und Nachteile jeder Methode können Sie Prototyping als "effizientere" Methode betrachten, da es eine Referenz für jede Instanz enthält, anstatt die gesamte Eigenschaft in jedem Objekt zu kopieren. Auf der anderen Seite ist es ein Beispiel für enge Kopplung, die ein großes Nein ist, bis Sie den Grund wirklich rechtfertigen können. thisist ziemlich kompliziert, da es für den Kontext relevant ist. Sie können viele gute Ressourcen kostenlos im Internet finden.

Alles in allem sind beide Möglichkeiten nur Sprachwerkzeuge und es hängt wirklich von Ihnen und dem Problem ab, das Sie zu lösen versuchen, um herauszufinden, was besser passt.

Wenn Sie eine Eigenschaft benötigen, die für jede Instanz einer Klasse relevant ist, verwenden Sie this. Wenn Sie eine Eigenschaft benötigen, die auf jeder Instanz gleich funktioniert, verwenden Sie prototype.

Aktualisieren

In Bezug auf Ihre Beispiel-Snippets ist der erste ein Beispiel für Singleton , daher ist es sinnvoll, ihn im Objektkörper zu verwenden this. Sie können Ihr Beispiel auch verbessern, indem Sie es so modular gestalten (und Sie müssen es nicht immer verwenden this).

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

Ihr zweites Snippet macht nicht viel Sinn, weil Sie es zuerst verwenden thisund später versuchen, es zu hacken prototype, was nicht funktioniert, weil es thisVorrang hat prototype. Ich bin mir nicht sicher, welche Erwartungen Sie an diesen Code hatten und wie er funktionierte, aber ich empfehle Ihnen dringend, ihn umzugestalten.

Aktualisieren

Um näher darauf thiseinzugehen, prototypekann ich Ihnen ein Beispiel zeigen und erklären, wie es erklärt werden kann, aber ich habe keine externe Ressource, um es zu sichern.

Das Beispiel ist sehr einfach:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

Die Erklärung ist, wie wir wissen, thiskontextbezogen. Es entsteht also erst, wenn der Kontext bereit ist. Wann ist der Kontext fertig? Wenn die neue Instanz erstellt wird! Sie sollten den Rest jetzt erraten! Das bedeutet, dass es zwar eine prototypeDefinition gibt, es jedoch thissinnvoller ist, Vorrang zu haben, da es sich nur um die neue Instanz handelt, die in diesem Moment erstellt wird.

53777A
quelle
Dies ist eine teilweise episch tolle Antwort! Können Sie es bearbeiten und die beiden Methoden genauer vergleichen und gegenüberstellen? Ihre ersten beiden Absätze verwirren mich, auf welche Entwurfsmethode Sie sich beziehen. Ihre Übung ist ausgezeichnet! Ich habe nie viel darüber nachgedacht, wie Prototypen gebaut werden können. Können Sie auch ein Beispiel für die Verwendung der einzelnen Methoden in einem halbdetailierten Fall geben? Nochmals vielen Dank, das ist großartig.
JDillon522,
@ JDillon522 Freut mich das zu hören. Ich werde versuchen, es in den nächsten Stunden zu aktualisieren!
53777A
@ JDillon522 Habe gerade ein schnelles Update gemacht. Hoffe es wird diesmal klarer.
53777A
@ JDillon522 Ein bisschen mehr über Ihre Beispielschnipsel ...
53777A
Nettes Singleton-Beispiel. Also habe ich thisim albernen Prototyp-Beispiel verwendet, weil es thissich auf seine eigenen Eigenschaften bezieht, einschließlich seiner Methoden. Ich lerne nicht das Beste aus dem Lesen von Code, sondern mehr aus dem Betrachten von Code. ( MDN ist ein bisschen drauf , Object Playground (erstaunlich) und ein paar andere). Können Sie auf etwas verweisen, das erklärt, was Sie unter " thisVorrang vor prototype" verstehen ? Ich würde gerne mehr darüber nachdenken.
JDillon522,