Hallo habr
Heute werden wir über ein sehr wichtiges Thema sprechen - die funktionale Programmierung. Die Bedeutung von FP in der modernen Webentwicklung ist kaum zu überschätzen. Die Architektur eines modernen Großprojekts umfasst benutzerdefinierte Funktionsbibliotheken, und im Interview werden auf jeder Ebene obligatorische Fragen zu FI gestellt.
Einführung in die funktionale Programmierung
Functional Programming (FP) ist eine Methode zum Organisieren von Code durch Schreiben einer Reihe von Funktionen.
EcmaScript ist eine Programmiersprache mit mehreren Paradigmen und implementiert unter anderem ein funktionales Paradigma. Dies bedeutet, dass Funktionen in ES Daten sind und an Funktionen übergeben, von Funktionen zurückgegeben und Funktionen selbst akzeptiert werden können. Das heißt Funktionen in ES sind
erstklassige Funktionen .
Daraus ergeben sich folgende Definitionen:
Funktionsargument (funarg) - ein Argument, dessen Wert eine Funktion ist.
Eine Funktion höherer Ordnung (FWP, Funktion höherer Ordnung, hof) ist eine Funktion, die Funktionen als Argumente akzeptiert.
Funktionen mit einem Funktionswert (Funktionswertfunktionen) - eine Funktion, die eine Funktion zurückgibt.
Alle diese Arten von Funktionen werden bedingt zu Funktionen der ersten Klasse zusammengefasst, und wie aus der obigen Definition hervorgeht, sind in ES alle Funktionen Objekte der ersten Klasse.
Pure Funktionen - das Ideal der funktionalen Programmierung
Reine Funktionen (PF) - geben immer ein vorhergesagtes Ergebnis zurück.
PF-Eigenschaften:
- Das Ergebnis der PF-Ausführung hängt nur von den übergebenen Argumenten und dem Algorithmus ab, der PF implementiert
- Verwenden Sie keine globalen Werte
- Ändern Sie keine externen Werte oder übergebenen Argumente
- Schreiben Sie keine Daten in Dateien, Datenbanken oder anderswo
Ein Beispiel für eine reine Funktion:
const add = (x,y) => x+y;
Ein gutes Beispiel für Funktionsverunreinigungen ist:
var first; var second; function testFn() { var a = 10; first = function() { return ++a; } second = function() { return --a; } a = 2; first();
Stellen Sie sich vor, wie kompliziert es ist, Tests für dieses Beispiel zu schreiben und wie sehr es sich für reine Funktionen vereinfacht!
Unreine Funktionen zeichnen sich durch einen zeitlich veränderlichen externen Zustand aus, der die Wartung, das Verständnis und das Testen von Code erschwert.
Im Gegenteil, reine Funktionen sind immer lesbar, testbar, vereinfachen die Parallelisierung von Berechnungen und sind einfach wiederzuverwenden.
Ich denke, Sie haben bemerkt, dass ich in den Beispielen für reine Funktionen auf die ES6-Syntax umgestellt habe. Dies wurde bewusst gemacht. Diese Funktionssyntax wird als "Pfeilfunktionen" bezeichnet, ist jedoch eine Implementierung der mathematischen Abstraktion, die vor langer Zeit erfunden wurde. Darüber weiter.
Lambda - Funktionen
Dies ist, was diese Pfeilform des Schreibens in der Mathematik und einigen anderen Programmiersprachen genannt wird. Die funktionale Programmierung ist sehr eng mit mat verbunden. Analyse, so wundern Sie sich nicht.
Der Begriff Lambda-Kalkül wurde bereits in den 1930er Jahren von der Alonzo-Kirche eingeführt. Im Wesentlichen ist die Lambda-Rechnung nichts anderes als eine formale Form der Beschreibung einer mathematischen Gleichung. Weitere Details
hier .
In ES implementiert eine Lambda-Funktion sehr oft einen Verschluss:
const add = x => y => x + y;
Kurz und prägnant. Die add-Funktion ist ein Lambda, das ein Argument x annimmt, es in einem Closure speichert und eine Funktion zurückgibt.
Vergleichen Sie mit diesem Code:
funtion add(x) { return function (y) { return x + y; } }
Offensichtlich sieht die erste Option besser aus.
Immunität
Unveränderlich (unveränderlich, Immunität) ist ein Objekt, dessen Zustand nach der Erstellung nicht mehr geändert werden kann. Das Ergebnis einer Änderung eines solchen Objekts ist immer ein neues Objekt, während sich das alte Objekt nicht ändert.
Unveränderlichkeit ist der goldene Gral der funktionalen Programmierung.
Betrachten Sie ein Beispiel:
const impureAddProp = (key, value, object) => { object[key] = value;
Wie Sie sehen können, haben wir in diesem Beispiel das Benutzerobjekt durch Hinzufügen einer Eigenschaft mutiert. Jetzt ist das User-Objekt eine Art „Shared State“ für die Funktion impureAddProp und andere Funktionen, die es mutieren. Dieser Ansatz ist schwieriger zu testen, weil Wenn Sie eine Funktion ändern, die mit einem gemeinsam genutzten Status interagiert, sollten Sie immer mögliche Fehler in anderen Funktionen berücksichtigen.
Aus Sicht der funktionalen Programmierung wäre es richtig:
const pureAddProp = (key, value, object) => ({ ...object, [key]: value }); const User= { name: 'Alex' }; const Admin= pureAddProp ('isAdmin', true, User);
Das User-Objekt bleibt also unverändert. Wir ändern eine Kopie der Daten, die immer sicher ist.
Fazit
Heute haben wir einige wichtige theoretische Konzepte untersucht. Wir haben uns mit reinen Funktionen, Lambda-Form der Aufnahmefunktionen und dem Konzept der Unveränderlichkeit in fp vertraut gemacht. Dieser Artikel ist jedoch eine Art Einführung. Die wichtigsten Ideen, Techniken und „harten Teile“ der funktionalen Programmierung werden in den folgenden Artikeln behandelt.
Funktionale Programmierung wird von vielen Bibliotheken implementiert. Dies ist Rambda und Lodash und viele andere. In einem realen Projekt werden Sie sie natürlich verwenden. Unter der Haube aller Bibliotheken wird es immer noch dasselbe native Javascript geben. In den folgenden Artikeln werden wir das FP analysieren und alle seine Konzepte auf nativem JS implementieren.
Nachtrag
Als ich anfing, Artikel zu schreiben, dachte ich an den folgenden Plan:
- Schreiben Sie Übersetzungen interessanter englischsprachiger Artikel
- Hervorheben mehrerer relevanter Bereiche in JS (Schlüsselkonzepte, OOP in Bezug auf EcmaScript-Spezifikationen, Muster, funktionale Programmierung).
Bisher wurden bereits Hauptartikel in drei Bereichen verfasst:
- this und ScopeChain in EcmaScript - hier habe ich Schlüsselkonzepte der Spezifikation wie den Ausführungskontext, das Schlüsselwort this und die Context-Eigenschaft ScopeChain (Bereichskette) beschrieben. Im Rahmen dieser Anweisung wurde mein Artikel über die lexikalische Umgebung und den Abschluss heute buchstäblich veröffentlicht.
- Ein Blick von EcmaScript auf die allgemeine Theorie der OOP - hier wurde der Unterschied zwischen statischer Klassentypisierung und dynamischer Prototyporganisation beschrieben, das delegierende Modell und die Ententypisierung wurden zerlegt
- Elegante Muster in modernem JavaScript (Bill Sourour-Kompilierungsserie zum Zyklus) - hier sind zwei Muster, die in bestimmten Situationen nützlich sein können. Mein Ansatz in Bezug auf Muster ist recht einfach: Es ist besser, so viele Muster wie möglich zu kennen, weil früher oder später nützlich sein
Und jetzt ist die funktionale Programmierung an der Reihe. In Zukunft werde ich Artikel in der Fortsetzung jedes dieser Bereiche schreiben. Der folgende Artikel befasst sich beispielsweise mit den Schlüsselkonzepten von OOP: Kapselung, Abstraktion, Verunreinigungen (und Striche), Schnittstellen usw. Ich möchte auch darüber sprechen, wie OOP in ES unter der Haube implementiert wird, d. H. über die Eigenschaften von Prototyp, Klasse und vieles mehr. Sprechen Sie darüber, wie v8 Entitäten und Instanzen von Klassen und Funktionen erstellt.
In den Kommentaren tauchen viele Fragen auf, daher möchte ich die Ziele erläutern, die ich mir für meine Artikel gesetzt habe. Ich schreibe keine Tutorials oder überprüfe die Dokumentation. Meiner Meinung nach macht das keinen Sinn. Ich rate Ihnen bei bestimmten Instrumenten oder Mustern nicht, ihre Wahl liegt ganz bei Ihnen.
In den Artikeln überprüfe ich entweder die Konzepte, erkläre, wie sie unter der Haube angeordnet sind (meiner Meinung nach verbessert dies das Verständnis für das, was wir schreiben und warum wir auf diese Weise schreiben), oder ich spreche über einige Dinge, die meinen Horizont erweitern. Meiner Meinung nach ist das sehr wichtig. Werfen Sie einen Blick auf Unternehmen wie Yandex oder Edadil, die ständig über originelle Ideen sprechen. Entweder sind dies Bitmaps in der Reaktion, dann ist die Vue-Anwendung fast vollständig auf es6-Klassen. Die meisten Webentwickler hätten niemals an so etwas gedacht. Dies erfordert einen breiten Ausblick.
Ich selbst habe das Web auf diese Weise studiert und studiert, d.h. Nachdem ich ein Tutorial oder ein Dock gelesen habe, versuche ich zu verstehen, wie das beschriebene Tool unter der Motorhaube funktioniert, um die internen Mechanismen zu verstehen.
Bis zu zukünftigen Artikeln, Freunde!