So implementieren Sie Funktions-Currying und -Decurrying in Javascript

So implementieren Sie Funktions-Currying und -Decurrying in Javascript

Funktion Currying (schwarzes Fragezeichen)? ? ? Currying (schwarzes Fragezeichengesicht)? ? ? Dies ist eine perfekte chinesische Übersetzung. Schauen wir uns an, was Funktionscurrying ist:

Wikipedia erklärt: Eine Technik, die eine Funktion, die mehrere Parameter akzeptiert, in eine Funktion umwandelt, die einen einzelnen Parameter akzeptiert (den ersten Parameter der ursprünglichen Funktion) und eine neue Funktion zurückgibt, die die verbleibenden Parameter akzeptiert und das Ergebnis zurückgibt. Es wurde vom Mathematiker Haskell Brooks Curry vorgeschlagen und nach Curry benannt.

Konzepte sind oft trocken und schwer zu verstehen. Lassen Sie es uns in menschlicher Sprache erklären: Wenn wir nicht sicher sind, wie viele Parameter diese Funktion hat, können wir ihr zuerst einen Parameter übergeben und dann JS-Closures verwenden (wenn Sie JS-Closures nicht verstehen, lernen Sie bitte Closure-Wissenspunkte, bevor Sie diesen Blog-Beitrag lesen https://www.cnblogs.com/dengyao-blogs/p/11475575.html), um eine Funktion zurückzugeben. Die interne Funktion empfängt die verbleibenden Parameter außer dem ersten Parameter für die Operation und Ausgabe. Dies ist das Currying der Funktion;

Hier ein kleines Beispiel:

Szenario (Anforderungen):

Wie wir alle wissen, machen Programmierer jeden Tag viele Überstunden. Wenn wir die täglichen Überstunden eines Programmierers berechnen müssen, sollte unsere erste Reaktion folgende sein:

var Überstunden=0;
Funktion Zeit(x){
    Rückgabe Überstunden+=x;
}

Zeit(1); //1
Zeit(2); //3
Zeit(3); //6

Mit dem obigen Code gibt es kein Problem, aber es ist sehr mühsam, bei jedem Aufruf die Uhrzeit hinzuzufügen, und bei jedem Aufruf der Funktion müssen bestimmte Vorgänge ausgeführt werden. Wenn die Datenmenge sehr groß ist, besteht möglicherweise die Gefahr, dass die Leistung beeinträchtigt wird. Gibt es also eine einfache Möglichkeit, das Problem zu lösen? manche!

Funktion Zeit(x){
  Rückgabefunktion (y) {
        gib x+y zurück;
    }      
}

var mal=Zeit(0);
mal(3);

Es gibt jedoch immer noch Probleme mit dem obigen Code. Bei der tatsächlichen Entwicklung sind unsere Parameter oft unsicher. Obwohl der obige Code einfach die grundlegende Operation des Curryings implementiert, kann er nicht mit Situationen umgehen, in denen die Parameter unsicher sind. Daher gibt es Einschränkungen bei den Funktionsparametern. Aus dem obigen Code können wir jedoch grundsätzlich erkennen, was Funktions-Currying bedeutet. Das heißt, wenn eine Funktion aufgerufen wird, darf nur ein Parameter übergeben werden. Anschließend wird die innere Funktion durch den Abschluss zurückgegeben, um die verbleibenden Parameter zu verarbeiten und zu empfangen. Die zurückgegebene Funktion merkt sich den ersten Parameter während des Abschlusses.

Lassen Sie uns den Code noch einmal transformieren:

// Definieren Sie zunächst eine Variable, die die Funktion empfängt var overtime = (function() {
//Definieren Sie ein Array zum Empfangen von Parametern var args = [];
//Closure wird hier verwendet, um eine externe Funktion aufzurufen, die eine interne Funktion zurückgibt return function() {
  //arguments ist ein im Browser integriertes Objekt, das speziell zum Empfangen von Parametern verwendet wird //Wenn die Länge des Parameters 0 ist, d. h. es gibt keinen Parameter if (arguments.length === 0) {
    //Variablen für die Akkumulation definieren var time = 0;
    //Schleifenakkumulation, vergleiche i mit der Länge von args for (var i = 0, l = args.length; i < l; i++) {
    //Die Akkumulationsoperation entspricht Zeit=Zeit+Argumente[i]
        Zeit += args[i];
      }
    //Gib das kumulierte Ergebnis zurück. Rückgabezeit;
    //Wenn die Länge des Argumentobjektparameters ungleich Null ist, d. h. wenn Parameter vorhanden sind}else {
    //Argumente als Array-Element zum definierten leeren Array hinzufügen. Der erste Parameter args wird verwendet, um den this-Zeiger zu ändern. Der zweite Parameter arguments fügt die verbleibenden Parameter als Array zum leeren Array hinzu [].push.apply(args, arguments);
    }
  }
})();

Verlängerung(3,5); // Tag 1 Verlängerung(4,5); // Tag 2 Verlängerung(2,1); // Tag 3//...

console.log( Überstunden() ); // 10.1

Der Code wurde geändert, um die Funktion zu erreichen, aber dies ist keine vollständige Implementierung der Funktion Currying. Wie können wir es also vollständig erreichen? Hier stellen wir eine allgemeine Implementierungsmethode vor:

//Definieren Sie die Curry-Methode, übergeben Sie zuerst einen Parameter var currying = function (fn) {
  //Definieren Sie ein leeres Array, um die restlichen Parameter des Argumentobjekts zusammenzustellen var args=[];
  //Verwende Closure, um eine Funktion zur Verarbeitung der restlichen Parameter zurückzugeben return function () {
    //Wenn die Länge der Argumente 0 ist, gibt es keine verbleibenden Parameter if(arguments.length===0){
    //Führe die obige Methode aus //Hier zeigt dies auf s unten, ähnlich wie s(), was bedeutet, dass die Funktion direkt aufgerufen wird, wenn die Parameterlänge 0 ist return fn.apply(this,args)
    }
    console.log(Argumente)
  //Wenn die Länge der Argumente nicht 0 ist, bleiben Parameter übrig //Fügen Sie dem Prototypobjekt des Arrays ein Array hinzu und ändern Sie den Zeiger davon mit „apply“ in „args“.
  //Fügen Sie das Array von [].slice.call(arguments) zum Prototyp-Array hinzu //Hier [].slice.call(arguments) === Array.prototype.slice.call(arguments) konvertiert das Argumentobjekt im Wesentlichen in ein Array mit Slice-Funktionalität Array.prototype.push.apply(args,[].slice.call(arguments))
    //args.push([].slice.call(Argumente))
    console.log(Argumente)
  //Die hier zurückgegebenen arguments.callee sind die zurückgegebene Abschlussfunktion. Callee ist eine Eigenschaft im Argumentobjekt, die verwendet wird, um das ausgeführte Funktionsobjekt zurückzugeben. return arguments.callee
  }
}
  //Hier wird die Currying-Methode aufgerufen und die Add-Funktion übergeben. Das Ergebnis gibt die Funktion innerhalb des Abschlusses zurück var s = currying(add);
  //Rufen Sie die Funktion innerhalb des Abschlusses auf. Wenn Parameter vorhanden sind, werden diese nach und nach zum Array args hinzugefügt. Wenn keine Parameter übergeben werden, wird es direkt aufgerufen. //Der Aufruf unterstützt Kettenoperationen s(1)(2)(3)();
//Sie können auch mehrere Parameter s(1,2,3) gleichzeitig übergeben;
  konsole.log(s());

Vorteile der JS-Funktion Currying:

  • Die Berechnung kann verzögert werden, d. h. wenn die Curry-Funktion mit Parametern aufgerufen wird, werden die Parameter zur Speicherung dem Array hinzugefügt und aufgerufen, wenn keine Parameter übergeben werden.
  • Wiederverwendung von Parametern: Wenn dieselbe Funktion mehrere Male aufgerufen wird und die meisten übergebenen Parameter gleich sind, ist die Funktion möglicherweise ein guter Kandidat für Currying.

Alles auf der Welt ist relativ, es gibt eine Ursache und eine Wirkung, und natürlich muss es, wenn es Currying gibt, auch Entcurrying geben.

Uncurrying ist im wahrsten Sinne des Wortes das Gegenteil von Currying. Tatsächlich besteht der eigentliche Zweck von Uncurrying darin, den Anwendungsbereich zu erweitern. Das heißt, wenn wir eine Methode aufrufen, müssen wir im Entwurfsprozess nicht berücksichtigen, ob das Objekt selbst diese Methode hat. Solange die Methode darauf anwendbar ist, können wir sie verwenden. (Hier ist die Idee des Ducktypings in dynamischen Sprachen)

Bevor wir uns mit JS-Anti-Currying befassen, lernen wir zunächst das Duck-Typing-Konzept dynamischer Sprachen kennen, um es besser zu verstehen:

Idee des Duck-Typings in dynamischer Sprache (Erklärung auf Wikipedia):

Ducktyping ist in der Programmierung eine Art der dynamischen Typisierung.

Bei diesem Stil wird die effektive Semantik eines Objekts nicht durch die Vererbung von einer bestimmten Klasse oder die Implementierung einer bestimmten Schnittstelle bestimmt, sondern durch den aktuellen Satz von Methoden und Eigenschaften.

Der Name dieses Konzepts stammt vom Ententest, der von James Whitcomb Riley vorgeschlagen wurde. Der „Ententest“ kann wie folgt ausgedrückt werden:

Wenn Sie einen Vogel sehen, der wie eine Ente läuft, wie eine Ente schwimmt und wie eine Ente quakt, dann kann man diesen Vogel als Ente bezeichnen.

Theoretische Erklärungen sind oft trocken und schwer zu verstehen. Um es menschlich auszudrücken: Sie sind der Sohn/die Tochter Ihrer Mutter. Egal, ob Sie ausgezeichnet oder schön sind, solange Sie das leibliche Kind Ihrer Mutter sind, sind Sie der Sohn/die Tochter Ihrer Mutter. Um es mit Ententypen auszudrücken: Solange Sie quaken und wie eine Ente laufen können, solange Sie sich wie eine Ente benehmen, können Sie als Ente bezeichnet werden, egal, ob Sie eine Ente sind oder nicht.

In Javascript gibt es viele Duck-Type-Referenzen. Wenn wir beispielsweise einer Variablen einen Wert zuweisen, müssen wir den Typ der Variablen offensichtlich nicht berücksichtigen. Aus diesem Grund ist Javascript flexibler und somit eine typische dynamisch typisierte Sprache.

Schauen wir uns an, wie beim Decurrying auf Ententypen verwiesen wird:

//Uncurring-Methode zum Funktionsprototypobjekt hinzufügen Function.prototype.uncurring = function() {
//Ändern Sie den Zeiger hiervon //Hier zeigt dies auf Array.prototype.push
  var selbst = dies;
    //Der Abschluss wird hier verwendet, um die Ausführung der inneren Funktion zurückzugeben return function() {
    //Erstelle eine Variable, füge shift zum Prototypobjekt des Arrays hinzu und lösche den ersten Parameter //Ändere das Array this in Argumente
    var obj = Array.prototype.shift.call(arguments);
    // Kehren Sie schließlich zur Ausführung zurück und ändern Sie die Methode so, dass sie auf obj zeigt, also auf Argumente
   // und Argumente als Parameter übergeben return self.apply(obj, arguments);
  };
};

//Uncurrying-Methode zum Array-Prototypobjekt hinzufügen var push = Array.prototype.push.uncurring();

//Test //Anonyme Funktion Selbstausführung (function() {
    //Das Push hier ist eine Funktionsmethode //Es entspricht der Übergabe von zwei Parametern, Argumenten und 4. In der obigen Shift-Methode wird jedoch der erste Parameter gelöscht und der Argumentparameter hier abgefangen, sodass am Ende tatsächlich nur 4 übergeben wird.
  push(Argumente, 4);
  console.log(Argumente); //[1, 2, 3, 4]
//Anonyme Funktion ruft sich selbst auf und nimmt die Parameter 1, 2, 3 entgegen
})(1, 2, 3)

An diesem Punkt können Sie darüber nachdenken. Argumente sind Objekte, die Parameter empfangen, und es gibt keine Push-Methode darin. Warum können Argumente also die Push-Methode aufrufen?

Dies liegt daran, dass der Code var push = Array.prototype.push.uncurring(); die uncurring-Methode zur Push-Methode des Array-Prototypobjekts hinzufügt und dann die anonyme Funktionsmethode push(arguments, 4); ausführt. Tatsächlich ruft er die obige Methode auf, um die uncurring-Methode zum Prototypobjekt von Function hinzuzufügen und eine auszuführende Closure-Innenfunktion zurückzugeben. Während des Ausführungsprozesses fängt die Shift-Methode des Array-Prototypobjekts die Argumente in push(arguments, 4); ab. Daher ist der eigentliche Methodenaufruf push(4), sodass das Endergebnis [1,2,3,4] ist.

Im Buch „JavaScript Design Patterns and Development Practices“ wird der Fall des Anti-Currying von JS-Funktionen wie folgt beschrieben:

//Definiere ein Objekt var obj = {
    "Länge": 1,
    "0":1
}
//Definieren Sie die Uncurrying-Methode im Funktionsprototypobjekt
Funktion.prototype.uncurrying = Funktion() {
    //dies zeigt auf Array.prototype.push
    var selbst = dies;
    //Der Abschluss gibt eine innere Funktion zurück return function() {
    // Dies kann in Teile zerlegt werden // Führen Sie zuerst apply return aus 
    //Funktion.prototype.call(Array.prototype.push[obj,2])
   //Dann Array.prototype.push.call(obj,2)
    //Aufruf ändert den Zeiger auf obj.push(2)
    //Das Endergebnis ist also {0: 1, 1: 2, Länge: 2}
        gibt Function.prototype.call.apply(self, arguments) zurück;
}
}

// in var push = Array.prototype.push.uncurrying()

drücken(Objekt, 2) 
konsole.log(obj);
//{0: 1, 1: 2, Länge: 2}

Die obige Methode ist schwer zu verstehen? Das ist egal, machen wir es verständlicher:

Funktion.prototype.unCurrying = Funktion () {
    var selbst = dies;
    Rückgabefunktion () {
    //[].slice.call(Argumente,1)===Array.prototype.push.slice.call(Argumente,1)===Argumente.slice(1)
returniere self.apply(Argumente[0], [].slice.call(Argumente, 1));
    };
};



var push = Array.prototype.push.uncurrying()
Konsole.log(push);
push(Objekt,2) //{0: 1, 1: 2, Länge: 2}
konsole.log(obj);

Lassen Sie es uns analysieren:

1. Fügen Sie zunächst die Uncurrying-Methode zum Funktionsprototypobjekt hinzu, damit alle Funktionen sie übernehmen können.

2. Geben Sie eine innere Closure-Funktion zurück

3. Das von der Closure-Funktion zurückgegebene Ergebnis ist die aufrufende Methode, self zeigt auf Array.prototype.push und der erste Parameter in der Apply-Methode ist der Änderungspunkt. Das folgende push(obj,2) entspricht dem Ändern des Punkts in obj.push(2).

4. Die Aufrufmethode des zweiten Parameters in der Apply-Methode wird so geändert, dass sie auf Argumente verweist, und die Slice-Methode kann in Argumenten verwendet werden, was gleich arguments.slice (1) ist.

Oben finden Sie Einzelheiten zur Implementierung von Funktions-Currying und -De-Currying in Javascript. Weitere Informationen zu Funktions-Currying und -De-Currying in Javascript finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Front-End-JavaScript versteht Funktions-Currying gründlich
  • Das Implementierungsprinzip und der Prozess des JavaScript-Funktionscurryings
  • Eine kurze Analyse der JavaScript-Funktion Currying
  • Analyse der Methoden und Beispiele für die Verwendung der JS-Funktion Currying
  • JavaScript implementiert Funktions-Currying und De-Currying-Prozessanalyse
  • Analyse des Prinzips und der Verwendung der JavaScript-Funktion Currying
  • Eine kurze Diskussion über Bind-Methoden und Funktions-Currying in JS
  • Eine kurze Analyse von Javascript-Closures und Function Currying
  • JavaScript-Funktion Currying erklärt
  • JavaScript-Funktion Currying

<<:  Mysql-Optimierung Zabbix-Partitionsoptimierung

>>:  Lösung für den Fall, dass der Tomcat-Server tomcat7w.exe nicht öffnen kann

Artikel empfehlen

Vue realisiert Web-Online-Chat-Funktion

In diesem Artikelbeispiel wird der spezifische Co...

So verwenden Sie async await elegant in JS

Inhaltsverzeichnis $.ajax von jQuery Der Beginn d...

Detaillierte Erläuterung der Js-Klassenkonstruktion und Vererbungsfälle

Die Definition und Vererbung von Klassen in JS si...

Ubuntu-Grundlagen-Tutorial: apt-get-Befehl

Vorwort Der Befehl apt-get ist ein Paketverwaltun...

So ändern Sie die Zeit in der virtuellen CentOS-Maschine

Das obere Bild zeigt die Systemzeit und das unter...

Analyse des Verwendungsbeispiels für den Common Table Expression CTE in mysql8

Dieser Artikel beschreibt anhand eines Beispiels ...

So überprüfen Sie die PCIe-Version und -Geschwindigkeit unter Linux

PCIE verfügt über vier verschiedene Spezifikation...

Detaillierte Erläuterung der Angular-Routing-Unterrouten

Inhaltsverzeichnis 1. Subroutensyntax 2. Beispiel...

Vue führt einen einfachen zufälligen Namensaufruf durch

Inhaltsverzeichnis Layoutteil: <div id="a...

WeChat-Applet zum Abrufen eines Schrittdatensatzes für Mobiltelefonnummern

Vorwort Kürzlich bin ich bei der Entwicklung eine...