JavaScript-Funktion Currying

JavaScript-Funktion Currying

1 Was ist Funktions-Currying?

In der Informatik ist Currying eine Technik zum Umwandeln einer Funktion, die mehrere Argumente akzeptiert, in eine Funktion, die ein einzelnes Argument akzeptiert (das erste Argument der ursprünglichen Funktion) und eine neue Funktion zurückgibt, die die verbleibenden Argumente akzeptiert und das Ergebnis zurückgibt. Die Technik ist nach dem Logiker Haskell Curry benannt.

Was bedeutet das? Einfach ausgedrückt ist Currying eine Technik zum Transformieren von Funktionen mit mehreren Parametern.

Zum Beispiel:

// Dies ist eine Funktion, die 3 Parameter akzeptiert const add = function(x, y, z) {
  gib x + y + z zurück
}


Wenn wir es transformieren, können wir eine Funktion wie diese erhalten:

// Akzeptiert einen einzelnen Parameter const curryingAdd = function(x) {
  // und gibt eine Funktion zurück, die die restlichen Parameter akzeptiert return function(y, z) {
    gib x + y + z zurück
  }
}


Welchen Unterschied macht das? Vergleich aus dem Anruf:

// Aufruf add
hinzufügen(1, 2, 3)
 
// Rufen Sie curryingAdd auf
curryingHinzufügen(1)(2, 3)
// Lassen Sie uns das genauer betrachten. Dies entspricht const fn = curryingAdd(1)
fn(2, 3)

Wie Sie sehen, kann die transformierte Funktion Parameter in Stapeln akzeptieren. Behalten Sie dies zunächst im Hinterkopf, da seine Nützlichkeit weiter unten erläutert wird. Sogar fn (die curryingAdd zurückgegebene Funktion) kann weiter transformiert werden

wie folgt:

const curryingAdd = Funktion(x) {
  Rückgabefunktion (y) {
    Rückgabefunktion (z) {
      gib x + y + z zurück
    }
  }
}
// Aufruf von curryingAdd(1)(2)(3)
// d. h. const fn = curryingAdd(1)
Konstante fn1 = fn(2)
fn1(3)

Bei den beiden oben genannten Transformationsprozessen handelt es sich um Funktionscurrying.

Einfach ausgedrückt transformiert es eine mehrparametrige Funktion f in eine Funktion g , die einige Parameter akzeptiert, und diese Funktion g gibt eine Funktion h zurück, die zum Akzeptieren anderer Parameter verwendet wird. Die Funktion h kann weiter gecurryt werden. Es handelt sich um einen Matrjoschka-Prozess.

Was bringt es also, sich die ganze Mühe zu machen, eine Funktion zu curryen?

2 Die Rolle und Eigenschaften des Currys

2.1 Wiederverwendung von Parametern

Anforderungen im Beruf: Überprüfen Sie die Rechtmäßigkeit von Telefonnummern, E-Mail-Adressen, Ausweisen usw. anhand regulärer Ausdrücke

Daher werden wir eine Verifizierungsfunktion wie folgt kapseln:

/**
 * @description Übergeben Sie den regulären Ausdrucksprüfstring* @param {RegExp} regExp reguläres Ausdrucksobjekt* @param {String} str Zu prüfender String* @return {Boolean} Gibt an, ob die Prüfung bestanden wurde*/
Funktion checkByRegExp(regExp, str) {
    return regExp.test(str)
}

Wenn wir viele Handynummern und E-Mail-Adressen verifizieren möchten, rufen wir es folgendermaßen auf:

// Überprüfen Sie die Telefonnummer checkByRegExp(/^1\d{10}$/, '15152525634'); 
checkByRegExp(/^1\d{10}$/, '13456574566'); 
checkByRegExp(/^1\d{10}$/, '18123787385'); 
// E-Mail prüfen checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]'); 
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]'); 
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]');

Es scheint kein Problem zu geben, aber es gibt noch Raum für Verbesserungen

  • Bei der Validierung desselben Datentyps schreiben wir denselben regulären Ausdruck viele Male.
  • Der Code ist nicht sehr lesbar. Ohne Kommentare können wir die Rolle der regulären Ausdrücke nicht sofort erkennen.

Versuchen wir, dies mithilfe der Funktion Currying zu verbessern:

// Curry die Funktion function checkByRegExp(regExp) {
    Rückgabefunktion (str) {
        return regExp.test(str)
    }
}


Wenn wir also verschiedene reguläre Objekte übergeben, können wir Funktionen mit unterschiedlichen Funktionen erhalten:

// Telefon prüfen const checkPhone = curryingCheckByRegExp(/^1\d{10}$/)
// E-Mail prüfen const checkEmail = curryingCheckByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/)


Jetzt ist der Code zur Verifizierung von Handy- und E-Mail-Adressen einfacher und lesbarer.

// Telefonnummer prüfen checkPhone('15152525634'); 
checkPhone('13456574566'); 
checkPhone('18123787385'); 
// E-Mail prüfen checkEmail('[email protected]'); 
checkEmail('[email protected]'); 
checkEmail('[email protected]');

Dies ist Parameterwiederverwendung: Wir müssen nur den ersten Parameter regExp wiederverwenden, um eine Funktion direkt mit einer bestimmten Funktion aufzurufen.

Universelle Funktionen (wie checkByRegExp ) lösen Kompatibilitätsprobleme, bringen aber auch Unannehmlichkeiten mit sich. Beispielsweise erfordern unterschiedliche Anwendungsszenarien die Übergabe mehrerer unterschiedlicher Parameter, um das Problem zu lösen.

Manchmal kann dieselbe Regel wiederholt verwendet werden (z. B. beim Überprüfen der Parameter eines Mobiltelefons), was zu Code-Duplikationen führt. Currying kann Duplikate vermeiden und den Zweck der Wiederverwendung von Parametern erreichen.

Eine wichtige Idee des Curryings: Anwendungsbereich reduzieren und Anwendbarkeit verbessern

2.2 Vorzeitige Rückgabe

Im JS DOM Ereignislistener verwenden wir die Methode addEventListener , um Elementen Ereignishandler hinzuzufügen, aber einige Browserversionen unterstützen diese Methode nicht, daher verwenden wir stattdessen die Methode attachEvent .

Jetzt schreiben wir einen Code, der mit jeder Browserversion kompatibel ist:

/**
 * @Beschreibung: 
 * @param {Objekt} Element DOM-Elementobjekt* @param {Zeichenfolge} Typ Ereignistyp* @param {Funktion} fn Ereignisverarbeitungsfunktion* @param {Boolean} isCapture, ob erfasst werden soll* @return {void}
 */
Funktion addEvent(Element, Typ, Funktion, isCapture) {
    wenn (window.addEventListener) {
        element.addEventListener(Typ, Funktion, isCapture)
    } sonst wenn (window.attachEvent) {
        element.attachEvent("ein" + Typ, fn)
    }
}

Wir verwenden addEvent , um Ereignislistener hinzuzufügen, aber jedes Mal, wenn diese Methode aufgerufen wird, wird eine Beurteilung vorgenommen. Tatsächlich ist nach der Ermittlung der Browserversion keine wiederholte Beurteilung erforderlich.

Curry:

Funktion curryingAddEvent() {
    wenn (window.addEventListener) {
        Rückgabefunktion (Element, Typ, fn, isCapture) {
            element.addEventListener(Typ, Funktion, isCapture)
        }
    } sonst wenn (window.attachEvent) {
        Rückgabefunktion (Element, Typ, fn) {
            element.attachEvent("ein" + Typ, fn)
        }
    }
}
const addEvent = curryingAddEvent()
 
// Sie können auch die Funktion zur sofortigen Ausführung verwenden, um den obigen Code zusammenzuführen const addEvent = (function curryingAddEvent() {
  ...
})()

Jetzt ist addEvent das wir erhalten, eine nach der Beurteilung erhaltene Funktion, und es besteht keine Notwendigkeit, die Beurteilung in zukünftigen Aufrufen zu wiederholen.

Dies ist eine frühzeitige Rückgabe oder frühzeitige Bestätigung. Nach dem Currying kann die Funktion einige Aufgaben im Voraus verarbeiten und eine Funktion zurückgeben, um andere Aufgaben zu verarbeiten.

Darüber hinaus können wir sehen, curryingAddEvent scheinbar keine Parameter akzeptiert. Dies liegt daran, dass die Bedingung der ursprünglichen Funktion (d. h. ob die Browserversion addEventListener unterstützt) direkt aus der globalen Funktion abgerufen wird.

Logischerweise kann es wie folgt geändert werden:

let-Modus = window.addEventListener? 0: 1;
Funktion addEvent(Modus, Element, Typ, fn, isCapture) {
  wenn (Modus === 0) {
    element.addEventListener(Typ, Funktion, isCapture);
  } sonst wenn (Modus === 1) {
    element.attachEvent("on" + Typ, fn);
  }
}
// Auf diese Weise können Sie nach dem Currying zuerst einen Parameter akzeptieren function curryingAddEvent(mode) {
    wenn (Modus === 0) {
        Rückgabefunktion (Element, Typ, fn, isCapture) {
            element.addEventListener(Typ, Funktion, isCapture)
        }
    } sonst wenn (Modus === 1) {
        Rückgabefunktion (Element, Typ, fn) {
            element.attachEvent("ein" + Typ, fn)
        }
    }
}

Natürlich besteht kein Grund, dies zu ändern.

2.3 Verzögerte Ausführung

Tatsächlich wurde die verzögerte Ausführung bereits in den obigen Beispielen für die reguläre Validierung und das Abhören von Ereignissen berücksichtigt.

Die Funktion curryingCheckByRegExp gibt nach dem Aufruf checkPhone und checkEmail zurück.

addEvent wird zurückgegeben, nachdem die Funktion curringAddEvent aufgerufen wurde.

Die zurückgegebene Funktion wird nicht sofort ausgeführt, sondern wartet auf den Aufruf.

3 Allgemeine Currying-Hilfsfunktionen einkapseln

Oben haben wir die ursprünglichen Funktionen für Currying manuell geändert, indem wir add curryingAdd , checkByRegExp in curryingCheckByRegExp und addEvent in curryingAddEvent geändert haben.

Müssen wir die zugrunde liegende Funktion jedes Mal manuell ändern, wenn wir eine Funktion curryen? Natürlich nicht

Wir können eine allgemeine Curry-Hilfsfunktion kapseln (handgeschriebener Code für das Interview)

/**
 * @description: Eine Tool-Funktion zum Curryen von Funktionen* @param {Funktion} fn Die Funktion, die curryen soll* @param {array} args Die Liste der bereits empfangenen Argumente* @return {Funktion}
 */
const currying = Funktion(fn, ...args) {
    // Die Anzahl der von fn benötigten Parameter const len ​​​​= fn.length
    // Gib eine Funktion zurück, um die restlichen Parameter zu erhalten return function (...params) {
        // Verkette die empfangenen und neu empfangenen Parameterlisten let _args = [...args, ...params]
        // Wenn die Anzahl der empfangenen Parameter nicht ausreicht, fahren Sie mit der Rückgabe einer neuen Funktion fort, um die verbleibenden Parameter zu empfangen, if (_args.length < len) {
            gibt currying.call(diese, fn, ..._args) zurück
        }
       //Nachdem wir alle Parameter erhalten haben, rufen wir die ursprüngliche Funktion auf. return fn.apply(this, _args)
    }
}

Diese Currying-Hilfsfunktion wird verwendet, um einige Parameter zu empfangen, dann eine neue Funktion zurückzugeben, die rekursiv auf die verbleibenden Parameter wartet, bis alle erforderlichen Parameter empfangen wurden, und dann die ursprüngliche Funktion über apply aufzurufen.

Nun müssen wir die ursprüngliche Funktion grundsätzlich nicht mehr manuell ändern, um die Funktion zu curryieren

// Verwende direkt die Tool-Funktion, um die Funktion zum Überprüfen der Telefonnummer und der E-Mail-Adresse zurückzugeben const checkPhone = currying(checkByRegExp(/^1\d{10}$/))
const checkEmail = currying(checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/))


Das obige Beispiel für die Ereignisüberwachung kann jedoch nicht mit dieser Hilfsfunktion curryed werden. Der Grund ist wie oben erwähnt. Da die Bedingungen direkt aus dem globalen Kontext abgerufen werden, ist es etwas ganz Besonderes. Wenn wir es ändern, um die Bedingungen von außen zu übergeben, können wir die Hilfsfunktion curryed verwenden. Dies ist natürlich nicht erforderlich. Es ist direkter und lesbarer, die ursprüngliche Funktion direkt zu ändern.

4 Zusammenfassung und Ergänzung

  • Currying hebt eine wichtige Idee hervor: Reduzierung des Anwendungsbereichs und Verbesserung der Anwendbarkeit
  • Drei Funktionen und Merkmale des Currying: Wiederverwendung von Parametern, frühzeitige Rückgabe und verzögerte Ausführung
  • Currying ist eine typische Anwendung von Closures, bei der Closures verwendet werden, um einen im Speicher abgelegten Bereich zu bilden, und einige der empfangenen Parameter in diesem Bereich für die spätere Verwendung gespeichert werden. Und geben Sie eine neue Funktion zurück, um die verbleibenden Parameter zu erhalten

Dies ist das Ende dieses Artikels über JavaScript Funktionscurrying. Weitere Informationen zum Funktionscurrying finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Ausführliche Erklärung zum Currying von JS-Funktionen
  • Eine kurze Analyse der JavaScript-Funktion Currying
  • Analyse der Methoden und Beispiele für die Verwendung der JS-Funktion Currying
  • JavaScript-Funktion Currying erklärt
  • JavaScript-Funktion Currying erklärt

<<:  Implementierung der MVCC-Mehrversions-Parallelitätskontrolle von MySQL

>>:  So implementieren Sie adaptive Container mit gleichem Seitenverhältnis mit CSS

Artikel empfehlen

So erhalten Sie die Schnittmenge/Differenz/Vereinigung zweier Mengen in MySQL

Typische MySQL-Szenarien: Schnittmenge und Differ...

Erste Schritte Tutorial für Anfänger ④: So binden Sie Unterverzeichnisse

Um zu verstehen, was das bedeutet, müssen wir zunä...

Detaillierte Erklärung unsichtbarer Indizes in MySQL 8.0

Wort Seit der ersten Version von MySQL 8.0 liegen...

So verwenden Sie die Shell, um Batchvorgänge auf mehreren Servern auszuführen

Inhaltsverzeichnis SSH-Protokoll SSH Verbindungsp...

Tutorial zum Erstellen eines SVN-Servers mit Docker

SVN ist die Abkürzung für Subversion, ein Open-So...

Axios storniert wiederholte Anfragen

Inhaltsverzeichnis Vorwort 1. So stornieren Sie e...

jQuery-Plugin für ein nahtloses Karussell

Ein nahtloses Karussell ist ein sehr häufiger Eff...

Teilen Sie 20 hervorragende Beispiele für Webformular-Design

Sophie Hardach Kai von Clyde Quay 37 Ost Seifenkis...

Lösen Sie das Problem beim Ausführen von Jupyter Notebook auf dem Server

Inhaltsverzeichnis Auf dem Server läuft Jupyter N...