Welche häufigen Programmierprobleme lassen sich am besten mit Prototypen und Verschlüssen lösen?

8

So gut ich beide Konzepte verstehe, kann ich nicht erkennen, wie ich die Verschlüsse und Prototypen von JavaScript nutzen kann, außer sie zum Erstellen instanziierbarer und / oder gekapselter klassenähnlicher Blöcke zu verwenden (was für mich eher eine Problemumgehung als ein Vorteil zu sein scheint )

Andere JS-Funktionen wie Funktionen als Werte oder die logische Bewertung von Nicht-Booleschen Werten lassen sich viel einfacher in ...

Welche häufigen Programmierprobleme lassen sich am besten mit propotypischer Vererbung und Verschlüssen lösen?

vemv
quelle
1
OO wird durch prototypische Vererbung gelöst. In JavaScript sind Prototypen Ihr OO-Mechanismus. Und Schließungen sind das, was Sie verwenden, um den Status an eine Funktion zu binden. Ich würde empfehlen, dass Sie node.js oder etwas anderes ausprobieren, das häufig asynchrone Logik verwendet. Sie werden sich leicht in Verschlüsse verlieben.
Raynos
Vielleicht habe ich mich nicht klar genug ausgedrückt - ich bin mir bereits bewusst, dass OO über Prototypen erreicht wird, aber es muss mehr Verwendungsmöglichkeiten für diese Funktion geben, nicht wahr? Fühlen Sie sich frei, einige Beispiele für asynchrone Logik zu nennen.
vemv
1
Sie lassen es so klingen, als wäre das Erreichen von OO über Prototypen eine kleine Leistung. "Prototypen müssen sicherlich mehr
Nutzen
2
@vemv: Prototypen sind da, um Ihnen OO zu geben. Zeitraum. Alles andere ist wirklich nur Missbrauch.
Jan Hudec
2
@vemv sie sind nicht exotisch, die Javascript-Community macht nur einen sehr schlechten Job beim Unterrichten von Prototypen Lesen Sie mehr über Protoypes
Raynos

Antworten:

5
  1. Verschlüsse machen Funktionen als Werte nützlich. Wenn Sie die Funktion übergeben, benötigen Sie sie mit ziemlicher Sicherheit, um einen Kontext mitzunehmen. Welches ist genau das, was Verschlüsse tun.

  2. Prototypen sind nur eine einfachere Version der Klassenvererbung. Anstatt Instanzen und Klassen zu haben (ohnehin durch spezielle Arten von Instanzen in dynamischen Sprachen dargestellt), haben Sie nur Instanzen und der Prototyp ist die Klasse (und sein Prototyp ist die Basisklasse). Sie lösen also im Grunde die gleichen Probleme, nur die Prototypen sind einfacher zu implementieren (deshalb hat JavaScript sie ausgewählt), etwas schwieriger zu verwenden (naja, nur Mangel an syntaktischem Zucker) und besser oder schlechter leichter zu missbrauchen.

Jan Hudec
quelle
"Wenn Sie Funktionen übergeben, brauchen Sie mit ziemlicher Sicherheit Kontext" nicht wirklich, schauen Sie sich C und ihre Funktionszeiger an, sie brauchen keinen Kontext. Wenn Sie Funktionen weitergeben, geben Sie diesen Funktionen im Allgemeinen den Kontext, den sie benötigen. Sicher, Schließungen sind eine großartige Möglichkeit, den Kontext
weiterzugeben
"Prototypen sind einfacher zu implementieren (deshalb hat JavaScript sie ausgewählt)." Das ist eine vage (und höchstwahrscheinlich falsche) Aussage ohne jegliche Referenz.
Raynos
@Raynos: In C übergeben wir häufig Kontext an Funktionen über ein void* dataArgument, das von der aufgerufenen Funktion heruntergestuft wird.
Kevin Cline
1
@ Raynos: Ich betrachte C-Funktionszeiger und sie sind äußerst schmerzhaft zu verwenden, es sei denn, der Code, der sie verwendet, durchläuft eine zusätzliche Leere * mit Kontext. Prototypen sind offensichtlich einfacher zu implementieren, da Sie nur eine Art von nicht primitiven Objekten und eine einheitliche Art des Zugriffs auf Mitglieder haben (und nicht getrennt von beispielsweise und Klassenmitgliedern und kein spezielles Verhalten von Metaobjekten). Obwohl ich keine Referenz habe, dass ECMAScript-Designer aus diesem Grund wirklich Prototypen ausgewählt haben, war ein minimaler Interpreter ein wichtiges Designziel, daher ist dies sehr wahrscheinlich.
Jan Hudec
@JanHudec Ich denke, es ist ein paar Größenordnungen wahrscheinlicher, dass JavaScript Prototypen hat, weil die prototypische OO-Sprache selbst brendan beeinflusst hat, als er Javascript schrieb.
Raynos
4

Closures lösen keine Programmierprobleme, die ohne sie nicht gelöst werden können. Dies kann jedoch für alle Sprachfunktionen gesagt werden, die für die Vollständigkeit von Turing nicht benötigt werden, sodass es nicht viel bedeutet.

Überlegen Sie, wie Sie Code, der einen Abschluss verwendet, neu schreiben müssen, um keinen Abschluss zu verwenden. Sie würden der Funktion mit dem Abschluss wahrscheinlich zusätzliche Eigenschaften geben, damit sie ihren Status zwischen den Aufrufen beibehalten kann. Das würde nur bedeuten, dass die Variablen, die sich bereits im Gültigkeitsbereich befinden, in gleichnamige Eigenschaften der Funktion kopiert werden. Es wäre also eine sinnlose Tippübung, die Sie dazu bringt, den Bildschirm anzuschreien. "Warum kann der dumme Compiler nicht ( Dolmetscher, was auch immer) finden Sie das heraus? " Das sind Schließungen, der dumme Compiler ist klug genug, um es herauszufinden.

psr
quelle
Gestern habe ich zum ersten Mal erkannt, wie Verschlüsse sinnvoll verwendet werden können - sie können die Trennung von Bedenken erheblich erleichtern: Eine Komponente würde eine anonyme Funktion an eine andere senden, wobei dieser Körper auf ein Feld verweist, das der zweiten Komponente nicht bekannt ist. Vielen Dank, dass Sie Compiler basiert!
vemv
@vemv - Was Sie ohne Verschlüsse tun könnten, indem Sie ein Objekt erstellen, das den Verweis auf das Feld enthält, das der zweiten Komponente nicht bekannt ist, und es an die zweite Komponente weitergeben, aber es ist im Vergleich zu einem Verschluss ein so großer Schmerz, dass Sie sich möglicherweise entscheiden es nicht zu tun.
Psr
2

Abschlüsse eignen sich hervorragend für asynchrone Logik.

Für mich geht es hauptsächlich um die Organisation von Code. Es ist schön, eine Reihe lokaler Funktionen zu haben, um aufzuteilen, was der Code tut.

create: function _create(post, cb) {
    // cache the object reference
    var that = this;

    function handleAll(err, data) {
        var rows = data.rows;

        var id = rows.reduce(function(memo, item) {
            var id = +item.id.split(":")[1];
            return id > memo ? id : memo;
        }, 0);
        id++;


        var obj = {
            title: post.title,
            content: post.content,
            id: id,
            // refer to the object through the closure
            _id: that.prefix + id,
            datetime: Date.now(),
            type: "post"
        }

        PostModel.insert(obj, handleInsert);
    }

    // this function doesn't use the closure at all.
    function handleInsert(err, post) {
        PostModel.get(post.id, handleGet);
    }

    // this function references cb and that from the closure
    function handleGet(err, post) {
        cb(null, that.make(post));
    }

    PostModel.all(handleAll);
}

Hier ist ein weiteres Beispiel für eine Schließung

var cachedRead = (function() {
    // bind cache variable to the readFile function
    var cache = {};

    function readFile(name, cb) {
        // reference cache
        var file = cache[name];
        if (file) {
            return cb(null, file);
        }

        fs.readFile(name, function(err, file) {
            if (file) cache[name] = file;
            cb.apply(this, arguments);
        });
    }

    return readFile;
})();

Und noch ein Beispiel

create: function _create(uri, cb, sync) {
    // close over count
    var count = 3;

    // next only fires cb if called three times
    function next() {
        count--;
        // close over cb
        count === 0 && cb(null);
    }

    // close over cb and next
    function errorHandler(err, func) {
        err ? cb(err) : next();
    }

    // close over cb and next
    function swallowFileDoesNotExist(err, func) {
        if (err && err.message.indexOf("No such file") === -1) {
            return cb(err);
        }
        next();
    }

    this.createJavaScript(uri, swallowFileDoesNotExist, sync)

    this.createDocumentFragment(uri, errorHandler, sync);

    this.createCSS(uri, swallowFileDoesNotExist, sync);
},

Die Alternative zur Verwendung von Verschlüssen besteht darin, Variablen mithilfe von Variablen in Funktionen zu curryen f.bind(null, curriedVariable).

Im Allgemeinen verwendet die asynchrone Programmierlogik jedoch Rückrufe, und die Manipulation des Status in Rückrufen beruht entweder auf Currying oder auf Schließungen. persönlich bevorzuge ich Verschlüsse.

Die Verwendung der prototypischen Vererbung ermöglicht OO? Muss die prototypische Vererbung wirklich mehr als das tun, damit sie als "nützlich" angesehen wird? Es ist ein Vererbungstool, es ermöglicht Vererbung, das ist nützlich genug.

Raynos
quelle