1. Ergänzende Wissenspunkte: implizite Konvertierung von FunktionenHier ist eine einfache Frage zum Nachdenken. Funktion fn() { Rückgabe 20; } console.log(fn + 10); // Was ist die Ausgabe? Ändern Sie es leicht und überlegen Sie, was das Ergebnis sein wird. Funktion fn() { Rückgabe 20; } fn.toString = Funktion() { Rückgabe 10; } console.log(fn + 10); // Was ist die Ausgabe? Sie können es weiterhin ändern. Funktion fn() { Rückgabe 20; } fn.toString = Funktion() { Rückgabe 10; } fn.valueOf = Funktion() { Rückgabe 5; } console.log(fn + 10); // Was ist die Ausgabe? // Die Ausgabeergebnisse sind die Funktion fn() { Rückgabe 20; } 10 20 15 Bei der Verwendung von console.log oder der Durchführung von Berechnungen können implizite Konvertierungen auftreten. Aus den obigen drei Beispielen können wir einige Schlussfolgerungen zur impliziten Konvertierung von Funktionen ziehen. Wenn wir toString und valueOf nicht neu definieren, ruft die implizite Konvertierung der Funktion die Standardmethode toString auf, die die Definition der Funktion als Zeichenfolge zurückgibt. Wenn wir die Methode toString/valuleOf aktiv definieren, wird das Rückgabeergebnis der impliziten Konvertierung von uns selbst gesteuert. Unter diesen hat valueOf eine höhere Priorität als toString. Daher ist die Schlussfolgerung des obigen Beispiels leicht zu verstehen. Ich empfehle Ihnen, es auszuprobieren. 2. Ergänzende Wissenspunkte: Map-Methode zum Einschließen von Arrays mithilfe von Call/Applymap(): Führt eine bestimmte Funktion für jedes Element in einem Array aus und gibt ein Array mit den Ergebnissen jedes Funktionsaufrufs zurück. Für Laien bedeutet dies, jedes Element des Arrays zu durchlaufen und das Berechnungsergebnis zurückzugeben, nachdem die Berechnungen im ersten Parameter der Map (Rückruffunktion) durchgeführt wurden. Gibt ein neues Array zurück, das aus allen Berechnungsergebnissen besteht. // Die Rückruffunktion enthält drei Parameter // Der erste Parameter repräsentiert jedes Element in newArr, der zweite Parameter repräsentiert den Indexwert des Elements im Array // Der dritte Parameter repräsentiert das Array selbst // Außerdem zeigt dies in der Rückruffunktion, wenn der zweite Parameter in der Map nicht vorhanden ist, auf das verlorene Objekt, wenn der zweite Parameter vorhanden ist, zeigt er auf das durch den Parameter festgelegte Objekt var newArr = [1, 2, 3, 4].map(function(item, i, arr) { console.log(item, i, arr, this); // Probieren Sie es aus return item + 1; // Füge zu jedem Element 1 hinzu }, { a: 1 }) console.log(newArr); // [2, 3, 4, 5] Die Details der Map-Methode werden in den Kommentaren im obigen Beispiel erläutert. Jetzt stehen wir vor einem schwierigen Problem: Wie lässt sich die Karte kapseln? Denken Sie zuerst an die For-Schleife. Wir können eine For-Schleife verwenden, um eine Map zu implementieren, aber bei der Kapselung müssen wir einige Aspekte berücksichtigen. Wenn wir die For-Schleife verwenden, lässt sich ein Schleifenprozess zwar leicht kapseln, es ist jedoch schwierig, das, was wir für jedes Element in der For-Schleife tun müssen, in einer festen Sache zu kapseln. Denn in jedem Szenario muss die Verarbeitung der Daten in der For-Schleife unterschiedlich sein. Daher haben wir uns eine gute Möglichkeit überlegt, diese verschiedenen Operationen mit einer separaten Funktion abzuwickeln, und diese Funktion zum ersten Parameter der Map-Methode gemacht. Die spezifische Operation in dieser Rückruffunktion wird bei ihrer Verwendung von uns selbst bestimmt. Daher ist die auf dieser Idee basierende Kapselungsimplementierung wie folgt. Array.prototype._map = Funktion(fn, Kontext) { vartemp = []; wenn(Typ von fn == 'Funktion') { var k = 0; var len = diese.Länge; // Kapsele den for-Schleifenprozess for(; k < len; k++) { // Jede Operation in fn einfügen und die Aufrufmethode verwenden, um den this-Zeiger und die spezifischen Parameter von fn anzugeben temp.push(fn.call(context, this[k], k, this)) } } anders { console.error('TypeError: '+ fn +' ist keine Funktion.'); } //Gibt ein neues Array zurück, das aus den Ergebnissen jeder Operation besteht. return temp; } var newArr = [1, 2, 3, 4]._map(Funktion(Element) { Artikel zurückgeben + 1; }) // [2, 3, 4, 5] Im obigen Paket habe ich zuerst ein leeres temporäres Array definiert, das zum Speichern der endgültigen Rückgabeergebnisse verwendet wird. In der For-Schleife wird der Parameter fn-Funktion bei jeder Ausführung der Schleife einmal ausgeführt und die Parameter von fn werden mithilfe der Call-Methode übergeben. Nachdem wir den Kapselungsprozess von map verstanden haben, können wir verstehen, warum wir bei der Verwendung von map immer einen Rückgabewert in der ersten Rückruffunktion erwarten. Wenn wir in den Eslint-Regeln bei der Verwendung von Map keinen Rückgabewert festlegen, wird dies als Fehler gewertet. Ok, da wir nun die impliziten Konvertierungsregeln von Funktionen verstehen und wissen, wie man in diesem Szenario „call/apply“ verwendet, können wir versuchen, Currying anhand eines einfachen Beispiels zu verstehen. 3. Currying vom Flachland in die TiefeEs gibt eine weit verbreitete Interviewfrage zum Currying in Front-End-Interviews. Implementieren Sie eine Add-Methode, sodass die Berechnungsergebnisse die folgenden Erwartungen erfüllen können:
Offensichtlich ist das Berechnungsergebnis die Summe aller Parameter. Jedes Mal, wenn die Add-Methode ausgeführt wird, muss sie dieselbe Funktion zurückgeben und mit der Berechnung der verbleibenden Parameter fortfahren. Wir können mit dem einfachsten Beispiel beginnen und Schritt für Schritt nach Lösungen suchen. Wenn wir es nur zweimal aufrufen, können wir es so kapseln. Funktion add(a) { Rückgabefunktion (b) { gib a + b zurück; } } konsole.log(hinzufügen(1)(2)); // 3 Wenn Sie es nur dreimal aufrufen: Funktion add(a) { Rückgabefunktion (b) { Rückgabefunktion (c) { gib a + b + c zurück; } } } konsole.log(hinzufügen(1)(2)(3)); // 6 Die obige Kapselung ähnelt ein wenig dem gewünschten Ergebnis, aber die Verwendung von Parametern ist sehr eingeschränkt, sodass dies nicht das gewünschte Endergebnis ist. Wir benötigen eine allgemeine Kapselung. Was sollte ich tun? Um die beiden obigen Beispiele zusammenzufassen: Wir verwenden tatsächlich die Eigenschaften von Abschlüssen, um alle Parameter in der am Ende zurückgegebenen Funktion zu konzentrieren, um die Ergebnisse zu berechnen und zurückzugeben. Daher besteht unser Hauptzweck beim Kapseln darin, die Parameter gemeinsam zu berechnen. Schauen wir uns die konkrete Implementierung an. Funktion add() { // Definieren Sie beim ersten Ausführen ein Array zum Speichern aller Parameter var _args = [].slice.call(arguments); // Deklariere eine Funktion darin, verwende die Closure-Funktion, um _args zu speichern und alle Parameterwerte zu sammeln. var adder = function () { var _adder = Funktion() { [].push.apply(_args, [].slice.call(Argumente)); gib _adder zurück; }; // Mithilfe der impliziten Konvertierungsfunktion wird bei der endgültigen Ausführung der Funktion eine implizite Konvertierung durchgeführt und der endgültige Wert berechnet und zurückgegeben _adder.toString = function () { return _args.reduce(Funktion (a, b) { gib a + b zurück; }); } gib _adder zurück; } returniere adder.apply(null, [].slice.call(Argumente)); } // Ergebnisse ausgeben, Parameter frei kombinierbar console.log(add(1, 2, 3, 4, 5)); // 15 console.log(add(1, 2, 3, 4)(5)); // 15 konsole.log(hinzufügen(1)(2)(3)(4)(5)); // 15 Die obige Implementierung nutzt die Eigenschaften von Closures. Der Hauptzweck besteht darin, alle Parameter in einem Array mithilfe einiger cleverer Methoden zu sammeln und während der abschließenden impliziten Konvertierung alle Elemente im Array zu addieren. Daher sind die Parameter beim Aufruf der Add-Methode sehr flexibel. Natürlich wurde es auch unseren Ansprüchen problemlos gerecht. Nachdem Sie nun die obige Demo verstanden haben, schauen wir uns die Definition von Currying an. Ich glaube, dass es für Sie leichter zu verstehen sein wird. Currying, auch als partielle Auswertung bekannt, ist 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 der Operation zurückgibt.
Im obigen Beispiel können wir add(1, 2, 3, 4) in add(1)(2)(3)(4) umwandeln. Dies ist eine Teilbewertung. Jedes Mal sind die übergebenen Parameter nur ein Teil aller Parameter, die wir übergeben möchten. Natürlich werden Parameter in tatsächlichen Anwendungen oft nicht so kompliziert verarbeitet. In vielen Fällen werden sie einfach in zwei Teile aufgeteilt. Lassen Sie uns über eine andere Frage zum Curry nachdenken. Angenommen, es gibt eine Berechnungsanforderung, die erfordert, dass wir jedes Element im Array mit den gewünschten Zeichen verbinden. Was sollen wir tun? Die Verwendung der Join-Methode ist ganz einfach. var arr = [1, 2, 3, 4, 5]; // In der tatsächlichen Entwicklung ist es nicht empfehlenswert, Array direkt mit neuen Methoden zu erweitern // Es ist nur eine Möglichkeit, es deutlicher zu demonstrieren Array.prototype.merge = function(chars) { gib dies zurück.join(Zeichen); } var Zeichenfolge = arr.merge('-') konsole.log(Zeichenfolge); // 1-2-3-4-5 Um den Schwierigkeitsgrad zu erhöhen, fügen Sie jedem Element eine Zahl hinzu und verbinden Sie sie dann miteinander. Dann benötigen wir hier eine Karte, die uns hilft, an jedem Element spezielle Operationen durchzuführen, ein neues Array zu generieren und diese dann mit Zeichen zu verbinden. Die Implementierung ist wie folgt: var arr = [1, 2, 3, 4, 5]; Array.prototype.merge = Funktion(Zeichen, Zahl) { gib dies zurück.map(Funktion(Element) { Retourenartikel + Nummer; }).join(Zeichen); } var Zeichenfolge = arr.merge('-', 1); console.log(Zeichenfolge); // 2-3-4-5-6 Was aber, wenn wir von jedem Element im Array ein Array subtrahieren und die Elemente dann miteinander verketten möchten? Die Implementierung ist natürlich dieselbe wie bei der obigen Additionsoperation. var arr = [1, 2, 3, 4, 5]; Array.prototype.merge = Funktion(Zeichen, Zahl) { gib dies zurück.map(Funktion(Element) { Artikelnummer zurücksenden; }).join(Zeichen); } var Zeichenfolge = arr.merge('~', 1); console.log(Zeichenfolge); // 0~1~2~3~4 Die schlauen Freunde müssen die Verwirrung bemerkt haben. Wir hoffen, eine Funktion kapseln zu können, die verschiedene Berechnungsprozesse gleichzeitig verarbeiten kann, wir können jedoch nicht jede einzelne Operation mit einer festen Routine kapseln. Es handelt sich also um das gleiche Problem wie bei der Kapselung einer Karte. Dies gelingt uns mit Hilfe des Curryings. Dasselbe Prinzip wie bei der Kartenkapselung. Da wir nicht im Voraus sicher sind, wie wir die einzelnen Daten verarbeiten werden, weiß ich nur, dass wir sie verarbeiten und dann mit Zeichen verbinden müssen. Daher können wir den Verarbeitungsinhalt auch gleich in einer Funktion speichern. Und es wird nur der Teil benötigt, der durch die Befestigung des Pakets verbunden wird. Wir haben also das folgende Paket. // Die Kapselung ist sehr einfach, ein Satz genügt Array.prototype.merge = function(fn, chars) { gib dies zurück.map(fn).join(chars); } var arr = [1, 2, 3, 4]; // Die Schwierigkeit liegt darin, wie die Operation im tatsächlichen Gebrauch definiert wird und wie mithilfe von Closure der übergebene Num-Parameter gespeichert wird. var add = function(num) { Rückgabefunktion (Element) { Artikel + Nummer zurückgeben; } } var rot = Funktion(num) { Rückgabefunktion (Element) { Artikel zurückgeben - Nr. } } // Zu jedem Element 2 hinzufügen und zusammenführen var res1 = arr.merge(add(2), '-'); // Von jedem Element 2 abziehen und zusammenführen var res2 = arr.merge(red(1), '-'); // Sie können die Rückruffunktion auch direkt verwenden, jedes Element mit 2 multiplizieren und sie zusammenführen var res3 = arr.merge((function(num) { Rückgabefunktion (Element) { Rücksendeartikel * Anzahl } })(2), '-') console.log(res1); // 3-4-5-6 console.log(res2); // 0-1-2-3 console.log(res3); // 2-4-6-8 Können Sie die Charakteristika des Currys anhand der obigen Beispiele erkennen? 4. Currying-VerallgemeinerungDie allgemeine Curry-Methode ist tatsächlich viel einfacher als die Add-Methode, die wir oben gekapselt haben. var currying = Funktion(fn) { var args = [].slice.call(Argumente, 1); return Funktion() { // Der Hauptzweck besteht darin, alle erforderlichen Parameter für eine einheitliche Berechnung in einem Array zu sammeln. var _args = args.concat([].slice.call(arguments)); gibt fn.apply(null, _args) zurück; } } var Summe = Currying (Funktion () { var args = [].slice.call(Argumente); returniere args.reduce(Funktion(a, b) { gib a + b zurück; }) }, 10) console.log(Summe(20, 10)); // 40 console.log(Summe(10, 5)); // 25 5. Curry und BindenObjekt.prototype.bind = Funktion(Kontext) { var _this = dies; var args = [].prototype.slice.call(arguments, 1); return Funktion() { returniere _this.apply(Kontext, Argumente) } } In diesem Beispiel wird die flexible Verwendung von „call“ und „apply“ genutzt, um die Bind-Funktion zu implementieren. In den vorherigen Beispielen können wir die Merkmale des Curryings zusammenfassen:
Ich hoffe, dass jeder nach der Lektüre ein allgemeines Verständnis des Curry-Konzepts hat. Wenn Sie es gekonnt anwenden möchten, müssen Sie über mehr praktische Erfahrung verfügen. Oben finden Sie eine ausführliche Erläuterung der Details zum Currying von JS-Funktionen. Weitere Informationen zum Currying von JS-Funktionen finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM! Das könnte Sie auch interessieren:
|
<<: Easyswoole Ein-Klick-Installationsskript und Pagoden-Installationsfehler
>>: Tiefgreifendes Verständnis des Statusübergangs des MySQL-Master-Slave-Replikationsthreads
„Wir schreiben unsere nächste Reihe mobiler Produ...
Zunächst müssen wir verstehen, dass GB2312, GBK u...
In diesem Artikel wird der spezifische Code von V...
1. Überprüfen Sie nach der Verbindung und Anmeldu...
Inhaltsverzeichnis 1. Szenariobeschreibung: 2. Fa...
Inhaltsverzeichnis Zuerst müssen wir das Seitenla...
Führen Sie den Befehl aus: glxinfo | grep renderi...
Inhaltsverzeichnis Vorwort Szenarioanalyse Zusamm...
Gespeicherte MySQL-Prozedur 1. Erstellen Sie die ...
Der Syntaxstil der CSS-Stilregel ist die Grundein...
ffmpeg ist ein sehr leistungsfähiges Tool zur Aud...
Hintergrund Da ich alle meine Aufgaben auf Docker...
1. Linklayout der neuen Site-Startseite 1. Die Pos...
Inhaltsverzeichnis Was ist bidirektionale Datenbi...
(Win7-System) Tutorial zur Installation einer vir...