A beginner friendly intro to functional programming
Functional programming is a highly valued approach to writing code, and it’s popularity is continuously increasing in kommerzielle Software-Anwendungen. Funktionale Programmierung ist ein Paradigma des Schreibens von Code und wird in der Einleitung dieses Wikipedia-Artikels eloquent formuliert:
“ – ein Stil zum Aufbau der Struktur und der Elemente von Computerprogrammen —, der die Berechnung als Auswertung mathematischer Funktionen behandelt und Zustandsänderungen und veränderliche Daten vermeidet. Es ist ein deklaratives Programmierparadigma, was bedeutet, dass die Programmierung mit Ausdrücken oder Deklarationen anstelle von Anweisungen erfolgt.“
Wir werden sehr bald darauf eingehen, was das genau bedeutet, aber lassen Sie uns zuerst die Grundlagen aus dem Weg räumen, indem wir einen Kontext bereitstellen. Dieser Artikel dient dem Zweck, Ihnen hoffentlich die grundlegenden Konzepte der funktionalen Programmierung vorzustellen, und am Ende haben wir ein grundlegendes Verständnis dafür entwickelt, warum wir es in unseren Codierungsstilen anwenden würden, wie es sich auf JavaScript bezieht und einige grundlegende Muster, die Sie in Ihren Code implementieren können. Halten Sie Ausschau nach einem zweiten Artikel, der auf diesem aufbaut und noch tiefer in die hier diskutierten Ideen eingeht.Die Wurzeln der funktionalen Programmierung liegen im Lambda-Kalkül, einem System, das in den 1930er Jahren entwickelt wurde, um Berechnungen mit Funktionen auszudrücken, die denen ähneln, die wir sehr bald sehen werden. Funktionale Programmierkonzepte und -sprachen wurden lange Zeit in akademischen und wissenschaftlichen Kontexten diskutiert und mündeten schließlich in die Entwicklung kommerzieller Software. Sprachen wie diese sind Ruby, Python, Julia und JavaScript, von denen letzteres Eigenschaften von imperativen, objektorientierten und funktionalen Paradigmen aufweist.
Schauen wir uns ein Beispiel für die Verwendung eines Imperativs und dann einen funktionalen Ansatz zum Ausführen einer einzelnen Aufgabe an.
Imperativ:
const arr = function getOdds(arr){
let odds = ; for(let i = 0; i < arr.length + 1; i++){
if ( i % 2 !== 0 ){
odds.push( i )
};
};
return odds
};console.log(getOdds(arr))
// logs
Funktional:
function getOdds2(arr){
return arr.filter(num => num % 2 !== 0)
}console.log(getOdds2(arr))
// logs // this can be even shorter
const getOdds3 = arr => arr.filter(num => num % 2 !== 0)console.log(getOdds3(arr))
// logs
Abgesehen von den offensichtlichen Verbesserungen, die der funktionale Ansatz macht, wie kürzerer Code, der uns ein paar Tastenanschläge erspart, und die Tatsache, dass es auf einen Blick viel einfacher zu verstehen ist, ist es auch elegant, was zu saubererem Code führt, Debugging, Testen und Wartung vereinfacht.
Lassen Sie uns dies ein wenig aufschlüsseln, damit wir die Unterschiede zwischen den beiden Ansätzen klar verstehen und definieren können, was funktionale Programmierung ist.
Im ersten Ansatz beschreiben wir zwingend jedes Ereignis, das stattfinden muss, damit wir die Aufgabe erfüllen können, die ungeraden Zahlen aus einem Array herauszufiltern. Innerhalb der Funktion erstellen wir ein leeres Array, in dem wir die ungeraden Zahlen speichern. Wir weisen es an, das Array zu durchlaufen, dann deklarieren wir eine Bedingung, wenn der aktuelle Index eine ungerade Zahl ist, schieben Sie ihn in den leeren. Die for-Schleife enthält nicht die letzte Zahl im Array, sondern nur die Zahlen, die dazu führen. Daher addieren wir +1, wenn wir die Anzahl der Iterationen definieren, die unsere Schleife ausführen muss.
Im zweiten Ansatz definieren wir einfach das Ergebnis, das wir sehen möchten, indem wir eine Methode namens filter verwenden und der Maschine erlauben, sich um alle dazwischen liegenden Schritte zu kümmern. Dies ist ein deklarativerer Ansatz. Wir erklären, was das Endergebnis sein muss, und wir den Rest für uns behandelt.
Jetzt können wir sehen, was die oben genannte Definition ausdrücken soll. Eine Art der Programmierung, die Deklarationen und Ausdrücke anstelle von Anweisungen verwendet. Diese Definition kratzt nur an der Oberfläche der funktionalen Programmierung, und wir werden kontinuierlich auf unserer Definition aufbauen, wenn unser Verständnis wächst.
Einige Unterschiede zwischen iterativen und funktionalen Ansätzen.
- Stilistisch definieren wir ein Problem und die Änderungen, die wir sehen möchten, anstatt es Schritt für Schritt zu erklären.
- Wir müssen den Status in unseren Funktionen nicht wie oben verwalten, wo wir den Status unseres leeren Arrays verwaltet haben.
- Wir müssen uns nicht so sehr um die Reihenfolge der Ausführung kümmern.
- Wir verwenden weniger Schleifen, Bedingungen und verwenden mehr eingebaute Methoden, wiederverwendbare Funktionen und Rekursion.
Mit diesem Ansatz schreiben wir letztendlich saubereren Code, der uns, wie oben erwähnt, beim Debuggen und bei der Wartung hilft. Es hält die Dinge modular und Abschnitte unseres Codes werden in kleinere Teile zerlegt, die wir problemlos testen können. Wir können Teile unseres Codes mithilfe von Hilfsfunktionen wiederverwenden und schließlich ist es ein effizienterer, mathematischer Ansatz zum Schreiben von Code.
Die Säulen: Unser Codierungs-Toolkit zum Schreiben von Funktionscode
Im Folgenden finden Sie einige wichtige Aspekte zum Schreiben von qualitativ hochwertigem Funktionscode. Da es sich hierbei um einen Überblick handelt, werden wir nicht zu sehr auf jeden eingehen, sondern nur einige Schlüsselmerkmale und ein Beispiel für jeden definieren.
Reine Funktionen:
Reine Funktionen geben einen Wert zurück, der ausschließlich auf dem basiert, was übergeben wurde. Die Idee dahinter ist, dass es sich um eine reine Funktion handelt, wenn sie immer das gleiche Ergebnis zurückgibt, wenn dieselben Werte übergeben werden, und keine Werte außerhalb des ts-Bereichs ändert, was sie unabhängig von jedem Status im System macht. Daher kann eine reine Funktion niemals Daten mutieren, keine Nebenwirkungen hervorrufen und kann leicht wiederverwendet werden. Ein Beispiel für eine nicht reine Funktion ist eine Funktion, die einen API-Aufruf ausführt oder ein unvorhersehbares Ergebnis zurückgibt.
Einfache unreine Funktion:
var tip = 0;function calculateTip( mealTotal ) {
tip = 0.15 * mealTotal;
}calculateTip( 150 )
console.log(tip)
Einfache reine Funktion:
function isPure(x,y) {
return x * y
}console.log(isPure(3,5));
Die reine Funktion gibt jedes Mal das genaue Ergebnis zurück und mutiert keine Daten außerhalb davon. Seien Sie also vorsichtig bei der Auswahl der Methoden, die in Ihren reinen Funktionen verwendet werden sollen. Wenn Sie beispielsweise zwei Arrays in Ihrer Funktion zusammenführen möchten, wie dies normalerweise in einem React Reducer der Fall ist, vermeiden Sie die Verwendung des Arrays.Prototyp.drücken( ) Methode. Stattdessen möchten Sie Array verwenden.Prototyp.concat( ) , wodurch der Status der alten Arrays beibehalten und ein neues für Ihre Verwendung zurückgegeben wird.
Funktionen höherer Ordnung:
In Javascript werden Funktionen als Objekte behandelt, daher können wir Funktionen wie jeden anderen Wert übergeben. Eine Funktion höherer Ordnung ist einfach eine Funktion, die mit anderen Funktionen arbeitet. Sie können eine Funktion als Eingabe aufnehmen oder als Ausgabe zurückgeben. Wir werden ein einfaches Beispiel in der folgenden Demonstration sehen.
Anonyme Funktionen:
Anonyme Funktionen sind sehr hilfreich, wenn wir Ad-hoc-Logik nach Bedarf definieren müssen. Wie der Name schon sagt, ist eine anonyme Funktion namenlos und wird meistens als Argument für eine Funktion als Ersatz für eine benannte Funktion, eine einer Variablen zugewiesene Funktion oder als Funktion in einer Funktion höherer Ordnung zurückgegeben. Seine Wurzeln liegen stark im Lambda-Kalkül und sind für alle funktionalen Programmiersprachen sehr wichtig.
Anonyme Funktion, die einer Variablen zugewiesen ist. Einfach weiterzugeben und bei Bedarf aufzurufen.
const myVar = function(){console.log(‘Anonymous function here!’)}myVar()
Anonyme Funktion als Argument
setInterval(function(){console.log(new Date().getTime())}, 1000);
Anonyme Funktionen innerhalb einer Funktion höherer Ordnung
function mealCall(meal){
return function(message){
return console.log(message + " " + meal + ‘!!’)
}
}const announceDinner = mealCall(‘dinner’)
const announceLunch = mealCall(‘breakfast’)announceDinner(‘hey!, come and get your’)
announceLunch(‘Rise and shine! time for’)
Rekursion
Rekursion ist eine bekannte funktionale Programmiertechnik. Eine rekursive Funktion ist einfach eine Funktion, die sich selbst aufruft und daher als Schleife fungiert, die denselben Code mehrmals ausführt. Es kommt jedoch mit einer Einschränkung, man muss vorsichtig sein, um unendliche Rekursionen zu vermeiden. Daher wird ein Basisfall benötigt, um ihm mitzuteilen, wann er aufhören soll. Rekursive Funktionen oder Algorithmen können beide mit Rekursion und Schleifen implementiert werden, aber es ist besser, Rekursion zu verwenden. Unten ist der bekannte Algorithmus zum Faktorisieren einer Zahl sowohl unter Verwendung von Rekursion als auch einer Schleife.
Rekursive Funktion
function factorialize(num){
if (num === 0 || num === 1){return 1;}
return (num * factorialize(num — 1));
}var result = factorialize(14);console.log(result);
Rekursion mit einer Schleife
function factorialize(num) {
if (num === 0 || num === 1){
return 1;
}
for (var i = num-1; i >= 1; i-- ) {
num *= i;
}
return num;
}
console.log(factorialize(6));
Wir haben einige der wesentlichen Bestandteile zum Schreiben von Funktionscode behandelt. Es ist nicht möglich, immer Funktionscode in eine Anwendung zu schreiben, aber die Vorteile sind groß, wenn sie so oft wie möglich verwendet werden. Frameworks wie Angular und React sind stark von der funktionalen Programmierung beeinflusst, und Bibliotheken wie Redux und Lodash ermöglichen es uns, die Vorteile davon zu nutzen.
Ressourcen, um mehr zu erfahren? Hier sind einige großartige Artikel und Ressourcen zum weiteren Lernen.
- Warum funktionale Programmierung in JavaScript lernen? von Eric Elliot
- Eloquent JavaScript von Marijn Haverbeke
- Also willst du ein funktionaler Programmierer sein von Charles Scalfani