Wandler: Ein leistungsstarkes Funktionskompositionsmuster
Jan 13, 2025 pm 02:28 PMalias:: Transducer: Ein leistungsstarkes Funktionskompositionsmuster
Notizbuch:: Wandler: 一種強(qiáng)大的函數(shù)組合模式
Karte & Filter
Die Semantik von Map ist ?Mapping“, was bedeutet, dass eine Transformation für alle Elemente in einer Menge einmal durchgeführt wird.
const list = [1, 2, 3, 4, 5] list.map(x => x + 1) // [ 2, 3, 4, 5, 6 ]
function map(f, xs) { const ret = [] for (let i = 0; i < xs.length; i++) { ret.push(f(xs[i])) } return ret }
map(x => x + 1, [1, 2, 3, 4, 5]) // [ 2, 3, 4, 5, 6 ]
Oben wird absichtlich eine for-Anweisung verwendet, um klar zum Ausdruck zu bringen, dass die Implementierung von Map vom Sammlungstyp abh?ngt.
Sequentielle Ausführung;
Sofortige Bewertung, nicht faul.
Schauen wir uns den Filter an:
function filter(f, xs) { const ret = [] for (let i = 0; i < xs.length; i++) { if (f(xs[i])) { ret.push(xs[i]) } } return ret }
var range = n => [...Array(n).keys()]
filter(x => x % 2 === 1, range(10)) // [ 1, 3, 5, 7, 9 ]
In ?hnlicher Weise h?ngt die Implementierung von Filter auch vom spezifischen Sammlungstyp ab, und die aktuelle Implementierung erfordert, dass xs ein Array ist.
Wie kann die Karte verschiedene Datentypen unterstützen? Zum Beispiel ?Set“, ?Map“ und benutzerdefinierte Datentypen.
Es gibt einen herk?mmlichen Weg: Er basiert auf der Schnittstelle (Protokoll) der Sammlung.
Unterschiedliche Sprachen haben unterschiedliche Implementierungen. JS bietet in dieser Hinsicht relativ schwache native Unterstützung, aber es ist auch machbar:
Iterieren Sie mit Symbol.iterator.
Verwenden Sie ?Object#contractor“, um den Konstruktor zu erhalten.
Wie unterstützen wir also abstrakt verschiedene Datentypen in?Push?
Sie imitiert die?ramdajs-Bibliothek und kann auf die benutzerdefinierte?@@transducer/step-Funktion zurückgreifen.
function map(f, xs) { const ret = new xs.constructor() // 1. construction for (const x of xs) { // 2. iteration ret['@@transducer/step'](f(x)) // 3. collection } return ret }
Array.prototype['@@transducer/step'] = Array.prototype.push // [Function: push]
map(x => x + 1, [1, 2, 3, 4, 5]) // [ 2, 3, 4, 5, 6 ]
Set.prototype['@@transducer/step'] = Set.prototype.add // [Function: add]
map(x => x + 1, new Set([1, 2, 3, 4, 5])) // Set (5) {2, 3, 4, 5, 6}
Mit dieser Methode k?nnen wir Funktionen wie?Map?,?Filter?usw. implementieren, die eher axial sind.
Der Schlüssel besteht darin, Vorg?nge wie Konstruktion, Iteration und Sammlung an bestimmte Sammlungsklassen zu delegieren, da nur die Sammlung selbst wei?, wie diese Vorg?nge ausgeführt werden.
function filter(f, xs) { const ret = new xs.constructor() for (const x of xs) { if (f(x)) { ret['@@transducer/step'](x) } } return ret }
filter(x => x % 2 === 1, range(10)) // [ 1, 3, 5, 7, 9 ]
filter(x => x > 3, new Set(range(10))) // Set (6) {4, 5, 6, 7, 8, 9}
komponieren
Es treten einige Probleme auf, wenn die obige Karte und der obige Filter in Kombination verwendet werden.
range(10) .map(x => x + 1) .filter(x => x % 2 === 1) .slice(0, 3) // [ 1, 3, 5 ]
Obwohl nur 5 Elemente verwendet werden, werden alle Elemente in der Sammlung durchlaufen.
Bei jedem Schritt wird ein Zwischensammlungsobjekt generiert.
Wir verwenden Compose, um diese Logik erneut zu implementieren
function compose(...fns) { return fns.reduceRight((acc, fn) => x => fn(acc(x)), x => x) }
Um die Komposition zu unterstützen, implementieren wir Funktionen wie ?Karte“ und ?Filter“ in Form von ?Curry“.
function curry(f) { return (...args) => data => f(...args, data) }
var rmap = curry(map) var rfilter = curry(filter) function take(n, xs) { const ret = new xs.constructor() for (const x of xs) { if (n <= 0) { break } n-- ret['@@transducer/step'](x) } return ret } var rtake = curry(take)
take(3, range(10)) // [ 0, 1, 2 ]
take(4, new Set(range(10))) // Set (4) {0, 1, 2, 3}
const takeFirst3Odd = compose( rtake(3), rfilter(x => x % 2 === 1), rmap(x => x + 1) ) takeFirst3Odd(range(10)) // [ 1, 3, 5 ]
Bisher ist unsere Implementierung klar und pr?gnant im Ausdruck, aber verschwenderisch in der Laufzeit.
Die Form der Funktion
Transformator
Die?Kartenfunktion in der Version?Curry sieht folgenderma?en aus:
const map = f => xs => ...
Das hei?t,?map(x => ...)?gibt eine Einzelparameterfunktion zurück.
const list = [1, 2, 3, 4, 5] list.map(x => x + 1) // [ 2, 3, 4, 5, 6 ]
Funktionen mit einem einzigen Parameter k?nnen einfach zusammengestellt werden.
Insbesondere sind die Eingaben dieser Funktionen ?Daten“, die Ausgabe sind die verarbeiteten Daten und die Funktion ist ein Datentransformator (Transformer).
function map(f, xs) { const ret = [] for (let i = 0; i < xs.length; i++) { ret.push(f(xs[i])) } return ret }
map(x => x + 1, [1, 2, 3, 4, 5]) // [ 2, 3, 4, 5, 6 ]
function filter(f, xs) { const ret = [] for (let i = 0; i < xs.length; i++) { if (f(xs[i])) { ret.push(xs[i]) } } return ret }
Transformer?ist eine Einzelparameterfunktion, die sich für die Funktionskomposition eignet.
var range = n => [...Array(n).keys()]
Reduzierer
Ein Reduzierer ist eine Zwei-Parameter-Funktion, die verwendet werden kann, um komplexere Logik auszudrücken.
filter(x => x % 2 === 1, range(10)) // [ 1, 3, 5, 7, 9 ]
Summe
function map(f, xs) { const ret = new xs.constructor() // 1. construction for (const x of xs) { // 2. iteration ret['@@transducer/step'](f(x)) // 3. collection } return ret }
Karte
Array.prototype['@@transducer/step'] = Array.prototype.push // [Function: push]
map(x => x + 1, [1, 2, 3, 4, 5]) // [ 2, 3, 4, 5, 6 ]
Filter
Set.prototype['@@transducer/step'] = Set.prototype.add // [Function: add]
nehmen
Wie implementiert man Take? Dies erfordert ?reduce“, um eine ?hnliche Funktionalit?t wie ?break“ zu haben.
map(x => x + 1, new Set([1, 2, 3, 4, 5])) // Set (5) {2, 3, 4, 5, 6}
function filter(f, xs) { const ret = new xs.constructor() for (const x of xs) { if (f(x)) { ret['@@transducer/step'](x) } } return ret }
filter(x => x % 2 === 1, range(10)) // [ 1, 3, 5, 7, 9 ]
Wandler
Endlich treffen wir unseren Protagonisten
überprüfen Sie zun?chst noch einmal die vorherige?Kartenimplementierung
filter(x => x > 3, new Set(range(10))) // Set (6) {4, 5, 6, 7, 8, 9}
Wir müssen einen Weg finden, die Logik, die vom oben erw?hnten Array (Array) abh?ngt, zu trennen und in einen Reduzierer zu abstrahieren.
range(10) .map(x => x + 1) .filter(x => x % 2 === 1) .slice(0, 3) // [ 1, 3, 5 ]
Die Konstruktion verschwand, die Iteration verschwand und auch die Sammlung von Elementen verschwand.
Durch einen Reduzierer enth?lt unsere Karte nur die Logik innerhalb ihrer Zust?ndigkeiten.
Schauen Sie sich den Filter noch einmal an
function compose(...fns) { return fns.reduceRight((acc, fn) => x => fn(acc(x)), x => x) }
Beachten Sie?rfilter?und den Rückgabetyp von?rmap?oben:
function curry(f) { return (...args) => data => f(...args, data) }
Es handelt sich eigentlich um einen Transfomer, dessen Parameter und Rückgabewerte Reduzierer sind, also ein Transducer.
Transformer ist zusammensetzbar, also ist auch Transducer zusammensetzbar.
var rmap = curry(map) var rfilter = curry(filter) function take(n, xs) { const ret = new xs.constructor() for (const x of xs) { if (n <= 0) { break } n-- ret['@@transducer/step'](x) } return ret } var rtake = curry(take)
in & umwandeln
Aber wie benutzt man den Wandler?
take(3, range(10)) // [ 0, 1, 2 ]
take(4, new Set(range(10))) // Set (4) {0, 1, 2, 3}
Wir müssen Iteration und Sammlung mithilfe eines Reduzierers implementieren.
const takeFirst3Odd = compose( rtake(3), rfilter(x => x % 2 === 1), rmap(x => x + 1) ) takeFirst3Odd(range(10)) // [ 1, 3, 5 ]
Es kann jetzt funktionieren und wir haben auch festgestellt, dass die Iteration ?on-demand“ erfolgt. Obwohl die Sammlung 100 Elemente enth?lt, wurden nur die ersten 10 Elemente iteriert.
Als n?chstes kapseln wir die obige Logik in eine Funktion.
const map = f => xs => ...
type Transformer = (xs: T) => R
Flie?en
Fibonacci-Generator.
Angenommen, wir haben eine Art asynchrone Datensammlung, beispielsweise einen asynchronen unendlichen Fibonacci-Generator.
data ->> map(...) ->> filter(...) ->> reduce(...) -> result
function pipe(...fns) { return x => fns.reduce((ac, f) => f(ac), x) }
const reduce = (f, init) => xs => xs.reduce(f, init) const f = pipe( rmap(x => x + 1), rfilter(x => x % 2 === 1), rtake(5), reduce((a, b) => a + b, 0) ) f(range(100)) // 25
Wir müssen die Funktion ?into“ implementieren, die die oben genannten Datenstrukturen unterstützt.
Posten Sie die Array-Version des Codes als Referenz daneben:
type Transformer = (x: T) => T
Hier ist unser Implementierungscode:
type Reducer = (ac: R, x: T) => R
Der Sammelvorgang ist derselbe, der Iterationsvorgang ist unterschiedlich.
// add is an reducer const add = (a, b) => a + b const sum = xs => xs.reduce(add, 0) sum(range(11)) // 55
Die gleiche Logik gilt für verschiedene Datenstrukturen.
Bestellungen
Wenn Sie aufmerksam sind, stellen Sie m?glicherweise fest, dass die Parameterreihenfolge der auf ?Curry“ basierenden Compose-Version und der auf Reducer basierenden Version unterschiedlich sind.
Curry-Version
const list = [1, 2, 3, 4, 5] list.map(x => x + 1) // [ 2, 3, 4, 5, 6 ]
function map(f, xs) { const ret = [] for (let i = 0; i < xs.length; i++) { ret.push(f(xs[i])) } return ret }
Die Ausführung der Funktion erfolgt rechtsassoziativ.
Wandlerversion
map(x => x + 1, [1, 2, 3, 4, 5]) // [ 2, 3, 4, 5, 6 ]
function filter(f, xs) { const ret = [] for (let i = 0; i < xs.length; i++) { if (f(xs[i])) { ret.push(xs[i]) } } return ret }
Referenz
Wandler kommen
Wandler – Clojure-Referenz
Das obige ist der detaillierte Inhalt vonWandler: Ein leistungsstarkes Funktionskompositionsmuster. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Hei?e KI -Werkzeuge

Undress AI Tool
Ausziehbilder kostenlos

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem v?llig kostenlosen KI-Gesichtstausch-Tool aus!

Hei?er Artikel

Hei?e Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Es gibt drei g?ngige M?glichkeiten, HTTP-Anforderungen in Node.js zu initiieren: Verwenden Sie integrierte Module, Axios und Knotenfetch. 1. Verwenden Sie das integrierte HTTP/HTTPS-Modul ohne Abh?ngigkeiten, das für grundlegende Szenarien geeignet ist, jedoch eine manuelle Verarbeitung von Datengen?hten und Fehlerüberwachung erfordert, z. 2.Axios ist eine auf Versprechen basierende Bibliothek von Drittanbietern. Es verfügt über eine kurze Syntax und leistungsstarke Funktionen, unterstützt Async/Auseait, automatische JSON -Konvertierung, Interceptor usw. Es wird empfohlen, asynchrone Anforderungsvorg?nge zu vereinfachen. 3.Node-Fetch bietet einen Stil ?hnlich dem Browser-Abruf, basierend auf Versprechen und einfacher Syntax

JavaScript -Datentypen sind in primitive Typen und Referenztypen unterteilt. Zu den primitiven Typen geh?ren String, Anzahl, Boolesche, Null, undefiniertes und Symbol. Die Werte sind unver?nderlich und Kopien werden bei der Zuweisung von Werten kopiert, sodass sie sich nicht gegenseitig beeinflussen. Referenztypen wie Objekte, Arrays und Funktionen speichern Speicheradressen, und Variablen, die auf dasselbe Objekt zeigen, wirkt sich gegenseitig aus. Typeof und Instanz k?nnen verwendet werden, um die Typen zu bestimmen, aber auf die historischen Probleme der TypeOfnull zu achten. Das Verst?ndnis dieser beiden Arten von Unterschieden kann dazu beitragen, einen stabileren und zuverl?ssigeren Code zu schreiben.

Hallo, JavaScript -Entwickler! Willkommen in den JavaScript -Nachrichten dieser Woche! Diese Woche konzentrieren wir uns auf: Oracas Markenstreit mit Deno, neue JavaScript -Zeitobjekte werden von Browsern, Google Chrome -Updates und einigen leistungsstarken Entwickler -Tools unterstützt. Fangen wir an! Der Markenstreit von Oracle mit dem Versuch von Deno Oracle, ein "JavaScript" -Marke zu registrieren, hat Kontroversen verursacht. Ryan Dahl, der Sch?pfer von Node.js und Deno, hat eine Petition zur Absage der Marke eingereicht, und er glaubt, dass JavaScript ein offener Standard ist und nicht von Oracle verwendet werden sollte

Cacheapi ist ein Tool, das der Browser zur Cache -Netzwerkanfragen bereitstellt, das h?ufig in Verbindung mit dem Servicearbeiter verwendet wird, um die Leistung der Website und die Offline -Erfahrung zu verbessern. 1. Es erm?glicht Entwicklern, Ressourcen wie Skripte, Stilbl?tter, Bilder usw. Zu speichern; 2. Es kann die Cache -Antworten entsprechend den Anfragen übereinstimmen. 3. Es unterstützt das L?schen bestimmter Caches oder das L?schen des gesamten Cache. 4.. Es kann Cache -Priorit?ts- oder Netzwerkpriorit?tsstrategien durch Servicearbeiter implementieren, die sich auf Fetch -Ereignisse anh?ren. 5. Es wird h?ufig für die Offline -Unterstützung verwendet, die wiederholte Zugriffsgeschwindigkeit, die Vorspannungs -Schlüsselressourcen und den Inhalt des Hintergrundaktualisierungss beschleunigen. 6. Wenn Sie es verwenden, müssen Sie auf die Cache -Versionskontrolle, Speicherbeschr?nkungen und den Unterschied zum HTTP -Caching -Mechanismus achten.

Versprechen ist der Kernmechanismus für den Umgang mit asynchronen Operationen in JavaScript. Das Verst?ndnis von Kettenanrufen, Fehlerbehebung und Kombination ist der Schlüssel zum Beherrschen ihrer Anwendungen. 1. Der Kettenaufruf gibt ein neues Versprechen durch .then () zurück, um asynchrone Prozessverkampferung zu realisieren. Jeder. Dann () erh?lt das vorherige Ergebnis und kann einen Wert oder ein Versprechen zurückgeben; 2. Die Fehlerbehandlung sollte .Catch () verwenden, um Ausnahmen zu fangen, um stille Ausf?lle zu vermeiden, und den Standardwert im Fang zurückgeben, um den Prozess fortzusetzen. 3. Combinatoren wie Promise.All () (erfolgreich erfolgreich erfolgreich nach allen Erfolg), Versprechen.Race () (Die erste Fertigstellung wird zurückgegeben) und Versprechen.Allsettled () (Warten auf alle Fertigstellungen)

JavaScript-Array-integrierte Methoden wie .Map (), .filter () und .Reduce () k?nnen die Datenverarbeitung vereinfachen. 1) .Map () wird verwendet, um Elemente eins in eins um Neuarrays zu konvertieren; 2) .Filter () wird verwendet, um Elemente durch Bedingung zu filtern; 3) .Reduce () wird verwendet, um Daten als einzelner Wert zu aggregieren; Missbrauch sollte bei der Verwendung vermieden werden, was zu Nebenwirkungen oder Leistungsproblemen führt.

Die Ereignisschleife von JavaScript verwaltet asynchrone Vorg?nge, indem sie Call -Stapel, Webapis und Task -Warteschlangen koordinieren. 1. Der Anrufstack führt synchronen Code aus, und wenn er auf asynchrone Aufgaben begegnet, wird er zur Verarbeitung an Webapi übergeben. 2. Nachdem das Webapi die Aufgabe im Hintergrund abgeschlossen hat, wird der Rückruf in die entsprechende Warteschlange (Makroaufgabe oder Micro -Aufgabe) eingebaut. 3. Die Ereignisschleife prüft, ob der Anrufstapel leer ist. Wenn es leer ist, wird der Rückruf aus der Warteschlange herausgenommen und zur Ausführung in den Anrufstapel geschoben. V. 5. Das Verst?ndnis der Ereignisschleife hilft zu vermeiden, den Haupt -Thread zu blockieren und die Codeausführungsreihenfolge zu optimieren.

Ereignisblasen verbreiten sich vom Zielelement nach au?en zum Vorfahrknoten aus, w?hrend Ereignisfassungen sich von der ?u?eren Schicht nach innen zum Zielelement ausbreiten. 1. Ereignisblasen: Nach dem Klicken auf das untergeordnete Element l?st das Ereignis den H?rer des übergeordneten Elements nach oben aus. Nach dem Klicken auf die Schaltfl?che gibt es beispielsweise zuerst die untergeordnete und dann entzündete Eltern aus. 2. Ereigniserfassung: Stellen Sie den dritten Parameter auf True ein, so dass der H?rer in der Erfassungsstufe ausgeführt wird, z. B. das Ausl?sen des Capture -Listeners des übergeordneten Elements, bevor Sie auf die Schaltfl?che klicken. 3. Praktische Verwendungszwecke umfassen ein einheitliches Management von Ereignissen für Kinderelemente, Vorverarbeitung und Leistungsoptimierung von Abfangen. V.
