So implementieren Sie eine Array-Lazy-Evaluation-Bibliothek in JavaScript

So implementieren Sie eine Array-Lazy-Evaluation-Bibliothek in JavaScript

Überblick

In der Programmiersprachentheorie ist Lazy Evaluation (englisch: Lazy Evaluation), auch übersetzt als Lazy Calculation, Lazy Evaluation, auch Call-by-Need genannt, ein Konzept der Computerprogrammierung. Sein Zweck besteht darin, den Arbeitsaufwand des Computers zu minimieren. Es hat zwei verwandte, aber unterschiedliche Bedeutungen, die als „verzögerte Auswertung“ und „minimierte Auswertung“ ausgedrückt werden können. Neben Leistungsverbesserungen besteht der wichtigste Vorteil der verzögerten Auswertung darin, dass ein unendlicher Datentyp erstellt werden kann.

Nachdem ich die Lazy Evaluation in funktionalen Sprachen gesehen hatte, wollte ich eine möglichst einfache Implementierung in JavaScript schreiben, um mein Verständnis der Lazy Evaluation zu vertiefen. Es werden zwei Methoden verwendet, die beide weniger als 80 Zeilen benötigen, um eine grundlegende Array-Lazy-Auswertung zu implementieren.

So erreichen Sie es

Bei der verzögerten Auswertung wird nicht bei jeder Auswertung ein Wert zurückgegeben, sondern eine Auswertungsfunktion mit Berechnungsparametern. Die Berechnung wird jedes Mal ausgeführt, wenn der Wert verwendet werden soll.

Wenn mehrere verzögerte Operationen vorhanden sind, wird eine Kette von Auswertungsfunktionen gebildet. Bei jeder Auswertung wertet jede Auswertungsfunktion die vorherige Auswertungsfunktion aus und gibt einen Wert zurück. Wenn die Berechnungsfunktion schließlich beendet wird, wird ein Beendigungswert zurückgegeben.

Konkrete Umsetzung

Bestimmen Sie die Beendigung der Bewertungsfunktion

Jede Auswertung der Funktion gibt unterschiedliche Daten zurück. Daher muss ein eindeutiger Wert als Markierung verwendet werden, um zu bestimmen, ob der Fluss abgeschlossen ist. Es kommt einfach vor, dass Symbol() ein neues Symbol erstellen kann, dessen Wert keinem anderen Wert entspricht.

const over = Symbol();

const istÜber = Funktion (_Über) {
  Rückgabewert _over === über;
}

Funktionsbereich generieren

Die Bereichsfunktion akzeptiert einen Start- und einen Endparameter, gibt eine Auswertungsfunktion zurück, führt die Auswertungsfunktion aus, um einen Wert zurückzugeben, und gibt den Endwert zurück, wenn sie beendet wird.

const range = Funktion (von, bis) {
  sei i = von;
  Rückgabefunktion () {
    wenn (i < bis) {
      ich++
      console.log('Bereich\t', i);
      Rückkehr ich
    }
    zurückkommen;
  }
}

Transformationsfunktionskarte

Akzeptiert eine Auswertungsfunktion und eine Verarbeitungsfunktion, ruft die Daten im Auswertungsfunktionsfluss ab, verarbeitet die Daten und gibt einen Fluss zurück.

const map = Funktion (Flow, Transform) {
  Rückgabefunktion () {
    const Daten = Fluss();
    console.log('map\t', Daten);
    gibt isOver(Daten) zurück? Daten: transformieren(Daten);
  }
}

Filter

Akzeptiert eine Auswertungsfunktion, filtert die Daten im Auswertungsfunktionsfluss, findet die passenden Daten und gibt sie zurück.

const filter = Funktion (Fluss, Bedingung) {
  Rückgabefunktion () {
    während(wahr) {
      const Daten = Fluss();
      wenn (isOver(data)) {
        Daten zurückgeben;
      }
      wenn(Bedingung(Daten)) {
        console.log('filter\t', Daten);
        Daten zurückgeben;
      }
    }
  }
}

Unterbrechungsfunktion stoppen

Akzeptiert eine Auswertungsfunktion und unterbricht, wenn eine bestimmte Bedingung erreicht ist. Sie können eine Abschlussfunktion plus eine Stoppfunktion verwenden und dann eine Take-Funktion implementieren.

const stop = Funktion (Fluss, Bedingung) {
  lass _stop = false;
  Rückgabefunktion () {
    wenn (_stop) zurückgeben;
    const Daten = Fluss();
    wenn (isOver(data)) {
      Daten zurückgeben;
    }
    _stop = Bedingung(Daten);
    Daten zurückgeben;
  }
}

const take = Funktion(Fluss, Num) {
  sei i = 0;
  Rückgabestopp (Flow, (Daten) => {
    gibt ++i >= num zurück;
  });
}

Sammlungsfunktion Join

Da alles, was zurückgegeben wird, eine Funktion ist, müssen wir am Ende eine Join-Funktion verwenden, um alle Werte zu sammeln und ein Array zurückzugeben.

const join = Funktion (Fluss) {
  konstantes Array = [];
  während(wahr) {
    const Daten = Fluss();
    wenn (isOver(data)) {
      brechen;
    }
    array.push(Daten);
  }
  Array zurückgeben;
}

prüfen:

const nums = join(take(filter(map(range(0, 20), n => n * 10), n => n % 3 === 0), 2));
console.log(Zahlen);

Ausgabe:

Bereich 1

Karte 1

Bereich 2

Karte 2

Bereich 3

Karte 3

Filter 30

Bereich 4

Karte 4

Bereich 5

Karte 5

Bereich 6

Karte 6

Filter 60

Eine elegantere Implementierung

Die verzögerte Auswertung wird mit den oben genannten Funktionen + Abschlüssen implementiert, ist aber immer noch nicht elegant genug. Der Großteil des Codes wird iteriert und beurteilt, ob die Auswertung abgeschlossen ist. Tatsächlich gibt es eine bessere Möglichkeit, in es6 eine verzögerte Auswertung zu erreichen, nämlich die Verwendung von Generatoren. Generatoren haben uns geholfen, Iterationen zu lösen und festzustellen, ob der Fluss abgeschlossen ist. Wir können uns auf die Logik konzentrieren und prägnanteren, leicht verständlichen und klar strukturierten Code schreiben.

const range = Funktion* (von, bis) {
  für(lass i = von; i < bis; i++) {
    console.log('Bereich\t', i);
    Ertrag i;
  }
}

const map = Funktion*(Fluss, Transformation) {
  für (const data of flow) {
    console.log('map\t', Daten);
    Ertrag(Transformation(Daten));
  }
}

const filter = funktion*(fluss, bedingung) {
  für (const data of flow) {
    console.log('filter\t', Daten);
    wenn (Bedingung(Daten)) {
      Ertragsdaten;
    }
  }
}

const stop = Funktion*(Fluss, Bedingung) {
  für (const data of flow) {
    Ertragsdaten;
    wenn (Bedingung(Daten)) {
      brechen;
    }
  }
}

const take = Funktion (Fluss, Zahl) {
  lass count = 0;
  const _filter = Funktion (Daten) {
    zählen++
    gibt Anzahl >= Zahl zurück;
  }
  Rückgabestopp (Flow, _Filter);
}

Vervollständigt wird es durch das Hinzufügen von Kettenaufrufen.

Klasse _Lazy{
  Konstruktor() {
    dieser.iterator = null;
  }

  Bereich(...args) {
    dieser.Iterator = Bereich(...args);
    gib dies zurück;
  }

  Karte(...args) {
    dieser.iterator = map(dieser.iterator, ...args);
    gib dies zurück;
  }

  filter(...args) {
    dieser.Iterator = Filter(dieser.Iterator, ...Argumente);
    gib dies zurück;
  }

  nehme(...args) {
    dieser.iterator = nehme(diesen.iterator, ...args);
    gib dies zurück;
  }

  [Symbol.iterator]() {
    gib diesen Iterator zurück;
  }

}

Funktion faul () {
  gibt neues _Lazy() zurück;
}

Zum Schluss testen Sie es noch einmal:

const nums = lazy().range(0, 100).map(n => n * 10).filter(n => n % 3 === 0).take(2);

für (sei n von Nums) {
  console.log('num:\t', n, '\n');
}

Ausgabe:

Bereich 0

Karte 0

Filter 0

Nummer: 0

Bereich 1

Karte 1

Filter 10

Bereich 2

Karte 2

Filter 20

Bereich 3

Karte 3

Filter 30

Zahl: 30

Okay, es ist erledigt.

Zusammenfassen

Auf diese Weise haben wir eine einfache Bibliothek für die verzögerte Array-Auswertung fertiggestellt. Hier implementieren wir lediglich die verzögerte Auswertung. Um sie in das Projekt einzufügen, müssen viele Details hinzugefügt werden. Da der Code nur 80 Zeilen umfasst, können Sie das Prinzip der Lazy Evaluation klar verstehen und Ihr Verständnis von Generatoren vertiefen.

Oben finden Sie Einzelheiten zur Implementierung einer Array-Lazy-Evaluation-Bibliothek mit JavaScript. Weitere Informationen zur Implementierung einer Array-Lazy-Evaluation-Bibliothek mit JavaScript finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Schreiben von wartbarem, objektorientiertem JavaScript-Code
  • Verwenden von JavaScript zum Erstellen von wartbarem Diashow-Code
  • Lassen Sie uns darüber sprechen, was das URL-Objekt von JavaScript ist
  • Detaillierte Erklärung der praktischen Anwendung regulärer Ausdrücke in JavaScript
  • Detaillierte Erklärung des Befehlsmodus in der Javascript-Praxis
  • So erstellen Sie Ihren eigenen nativen JavaScript-Router
  • So lernen Sie algorithmische Komplexität mit JavaScript
  • Verwenden Sie einige Interviewfragen, um den Ausführungsmechanismus von JavaScript zu untersuchen
  • Bringen Sie Ihnen bei, wie Sie wartbaren JS-Code schreiben

<<:  MySQL-Tutorial zum Bereitstellen mehrerer Instanzen auf einer einzigen Maschine mit mysqld_multi

>>:  So erstellen Sie eine lnmp-Umgebung im Docker

Artikel empfehlen

Detailliertes Tutorial zum Erstellen eines Gitlab-Servers auf CentOS8.1

Über den Unterschied zwischen Gitlab und Github m...

vite2.x implementiert das On-Demand-Laden von Ant-Design-Vue@next-Komponenten

1. Version verwenden vite:2.0 Ant-Design-Vue: 2.0...

Informationen zur Installation des Python3.8-Images im Docker

Offizielle Docker Hub-Website 1. Suchen Sie nach ...

vue+el-upload realisiert den dynamischen Upload mehrerer Dateien

vue+el-upload Dynamischer Upload mehrerer Dateien...

Gängige Stile von CSS-Animationseffekten

Animation Definieren Sie eine Animation: /*Legen ...

MySQL effiziente Abfrage Left Join und Gruppieren nach (plus Index)

MySQL effiziente Abfrage MySQL verzichtet auf „Gr...

Schaltflächen und Dropdown-Menüs für Studiennotizen in Bootstrap 3.0

Der vorherige Artikel war eine einfache Überprüfu...

So ändern Sie in Nginx die über http aufgerufene Website in https

Inhaltsverzeichnis 1. Hintergrund 2. Voraussetzun...

So implementieren Sie den Vue-Timer

In diesem Artikelbeispiel wird der spezifische Co...

Antworten auf mehrere häufig gestellte MySQL-Interviewfragen

Vorwort: Bei Vorstellungsgesprächen für verschied...

TimePicker im Element deaktiviert einen Teil der Zeit (deaktiviert auf Minuten)

Die Projektanforderungen lauten: Datum und Uhrzei...

Installationsprozess des mysql5.6.8-Quellcodes

Kernel: [root@opop ~]# cat /etc/centos-release Ce...