JavaScript-Objekte und Crockfords The Good Parts

8

Ich habe in letzter Zeit ziemlich viel darüber nachgedacht, wie man OOP in JS macht, insbesondere wenn es um Kapselung und Vererbung geht.

Laut Crockford ist klassisch aufgrund von new () schädlich, und sowohl prototypisch als auch klassisch sind begrenzt, da die Verwendung von constructor.prototype bedeutet, dass Sie keine Verschlüsse für die Kapselung verwenden können.

Kürzlich habe ich die folgenden Punkte zur Kapselung berücksichtigt:

  1. Die Kapselung beeinträchtigt die Leistung . Sie können Funktionen zu JEDEM Mitgliedsobjekt und nicht zum Prototyp hinzufügen, da die Methoden jedes Objekts unterschiedliche Abschlüsse haben (jedes Objekt hat unterschiedliche private Mitglieder).

  2. Durch die Kapselung wird die hässliche Problemumgehung "var that = this" erzwungen, damit private Hilfsfunktionen Zugriff auf die Instanz erhalten, an die sie angehängt sind. Entweder das oder stellen Sie sicher, dass Sie sie jedes Mal mit privateFunction.apply (this) aufrufen.

Gibt es Problemumgehungen für eines der beiden von mir genannten Probleme? Wenn nicht, halten Sie die Kapselung dennoch für lohnenswert?

Nebenbemerkung: Mit dem von Crockford beschriebenen Funktionsmuster können Sie nicht einmal öffentliche Methoden hinzufügen, die nur öffentliche Mitglieder berühren, da auf die Verwendung von new () und constructor.prototype vollständig verzichtet wird. Wäre ein hybrider Ansatz, bei dem Sie klassische Vererbung und new () verwenden, aber auch Super.apply (dies, Argumente) aufrufen, um private Mitglieder und privilegierte Methoden zu initialisieren, nicht überlegen?

Jonathan
quelle
Ich denke, es gibt einige JavaScript-Bibliotheken, die all dies bieten, z . B. Dojo . Es gibt auch TypeScript .
MarkJ
Das Klassensystem von @MarkJ Dojo scheint mit den millionenfach pseudoklassischen Vererbungsbibliotheken identisch zu sein und bietet in Bezug auf die Kapselung nichts.
Jonathan
Übrigens spielt dieser Artikel die Speichernutzung herunter. Es wird überhaupt nicht berücksichtigt, dass die Speichernutzung mit der Anzahl der Methoden zunimmt . Wenn er beispielsweise 20 Methoden in der "Klasse" hätte, würde das Funktionsmuster mit seinen Zahlen 3000 MB dauern, aber der Prototyp würde unabhängig davon immer noch 150 MB benötigen die Anzahl der Methoden. Es ist wie der Vergleich O(1)zu O(n)mit n = 2...
Esailija

Antworten:

2

Die Kapselung ist wirklich schwierig und wahrscheinlich die Mühe in JavaScript nicht wert. Eine Methode, die funktioniert und alles tut, was Sie sich wünschen (private Felder, Zugriff auf die Oberklasse und private Methoden), wäre diese (wahrscheinlich sehr hässliche und verbesserungsfähige) Lösung:

function SomeClass() {

    var parent = SomeSuperClass(),
        somePrivateVar;

    return Object.create(parent, {
        somePrivateVar: {
            get: function() {
                return somePrivateVar;
            },
            set: function(value) {
                somePrivateVar = value;
            }
        },
        doSomething: {
            value: function(data) {
                someHelperFunction.call(this, data);
            }
        }
    });
}

function someHelperFunction(data) {
    this.someMethod(data);
}

Diese Art von Arbeiten ermöglicht es Ihnen, private Felder und Methoden sowie Vererbung zu haben, wie man es erwarten würde. Ich mag es jedoch nicht - aber ich mag es am besten von allen Möglichkeiten, die Sie in reinem JavaScript haben.

Wenn ich ein neues Projekt mit viel JavaScript starten müsste, würde ich mir TypeScript wahrscheinlich genauer ansehen . Es verbessert JavaScript bei Bedarf (IMHO), gibt Ihnen statische Typisierung, Vererbung, Kapselung und alles. Aber es ist schließlich nur JavaScript.


Lohnt es sich jetzt? Ich denke, es gibt zwei wichtige Dinge zu beachten. Die Kapselung hilft Ihnen wahrscheinlich zur Entwicklungszeit, aber zur Laufzeit sicherlich nicht. Ich denke du musst dich entscheiden; Entweder keine Kapselung und bessere Leistung, oder Kapselung, nicht so schöner Code, wahrscheinlich ein besseres Design, aber etwas Overhead zur Laufzeit.

Bruno Schäpper
quelle
Ich bin mir dieses Musters bewusst: Es ist das, was Crockford als funktional bezeichnet, mit dem kleinen Unterschied, dass Sie den Elternteil als Prototyp des Kindes festlegen. Die Frage ist genau: Ist die Kapselung den in meinem OP erwähnten Overhead wert (und in Ihrem Code vorhanden)? Gibt es eine Möglichkeit, den besagten Overhead zu umgehen? TypeScript scheint interessant zu sein, da die Überprüfung der Kapselung zur Kompilierungszeit erfolgt, was bedeutet, dass das kompilierte JS keinen Overhead enthält, aber ich bleibe vorerst bei rohem JS. Übrigens sollte Ihr Code aus Konsistenzgründen wahrscheinlich var parent = SomeSuperClass () ohne new lesen.
Jonathan
@ Jonathan: Ich habe einige weitere Informationen zur "Wert" -Frage hinzugefügt.
Bruno Schäpper