Was ist eine reine Funktion in JavaScript?

Reine Funktionen sind die atomaren Bausteine ​​in der funktionalen Programmierung. Sie werden für ihre Einfachheit und Testbarkeit geliebt.

Dieser Beitrag enthält eine kurze Checkliste, um festzustellen, ob eine Funktion rein ist oder nicht.

Die Checkliste

Eine Funktion muss zwei Tests bestehen, um als „rein“ zu gelten:

  1. Gleiche Eingänge geben immer gleiche Ausgänge zurück
  2. Keine Nebenwirkungen

Lassen Sie uns jeden einzelnen vergrößern.

1. Gleicher Eingang => Gleicher Ausgang

Vergleichen Sie dies:

const add = (x, y) => x + y; add(2, 4); // 6 

Dazu:

let x = 2; const add = (y) => { x += y; }; add(4); // x === 6 (the first time) 

Reine Funktionen = konsistente Ergebnisse

Das erste Beispiel gibt einen Wert zurück, der auf den angegebenen Parametern basiert, unabhängig davon, wo / wann Sie ihn aufrufen.

Wenn Sie bestehen 2und erhalten 4, werden Sie immer bekommen 6.

Nichts anderes beeinflusst die Ausgabe.

Unreine Funktionen = inkonsistente Ergebnisse

Das zweite Beispiel gibt nichts zurück. Es ist auf den gemeinsamen Status angewiesen , um seine Aufgabe zu erfüllen, indem eine Variable außerhalb ihres eigenen Bereichs erhöht wird.

Dieses Muster ist der Alptraumbrennstoff eines Entwicklers.

Der gemeinsame Zustand führt eine Zeitabhängigkeit ein. Sie erhalten unterschiedliche Ergebnisse, je nachdem, wann Sie die Funktion aufgerufen haben. Das erste Mal ergibt 6, das nächste Mal ist 10und so weiter.

Über welche Version lässt sich leichter nachdenken?

Welches ist weniger wahrscheinlich, Fehler zu züchten, die nur unter bestimmten Bedingungen auftreten?

Welche ist in einer Multithread-Umgebung, in der Zeitabhängigkeiten das System beschädigen können, am wahrscheinlichsten erfolgreich?

Auf jeden Fall der erste.

2. Keine Nebenwirkungen

Dieser Test selbst ist eine Checkliste. Einige Beispiele für Nebenwirkungen sind

  1. Mutieren Sie Ihre Eingabe
  2. console.log
  3. HTTP-Aufrufe (AJAX / fetch)
  4. Ändern des Dateisystems (fs)
  5. Abfrage des DOM

Grundsätzlich jede Arbeit, die eine Funktion ausführt, die nicht mit der Berechnung der endgültigen Ausgabe zusammenhängt.

Hier ist eine unreine Funktion mit einem Nebeneffekt.

Nicht so schlecht

const impureDouble = (x) => { console.log('doubling', x); return x * 2; }; const result = impureDouble(4); console.log({ result }); 

console.logist der Nebeneffekt hier, aber in der Praxis wird es uns nicht schaden. Wir werden immer noch die gleichen Ausgaben erhalten, wenn die gleichen Eingaben vorliegen.

Dies kann jedoch ein Problem verursachen.

"Unrein" Ändern eines Objekts

const impureAssoc = (key, value, object) => { object[key] = value; }; const person = { name: 'Bobo' }; const result = impureAssoc('shoeSize', 400, person); console.log({ person, result }); 

Die Variable person,, wurde für immer geändert, da unsere Funktion eine Zuweisungsanweisung eingeführt hat.

Geteilter Zustand bedeutet impureAssoc, dass die Auswirkungen nicht mehr ganz offensichtlich sind. Um die Auswirkungen auf ein System zu verstehen, müssen Sie jetzt jede Variable aufspüren, die jemals berührt wurde, und ihre Historien kennen.

Geteilter Zustand = Zeitabhängigkeiten.

Wir können reinigen, impureAssocindem wir einfach ein neues Objekt mit unseren gewünschten Eigenschaften zurückgeben.

Reinige es

const pureAssoc = (key, value, object) => ({ ...object, [key]: value }); const person = { name: 'Bobo' }; const result = pureAssoc('shoeSize', 400, person); console.log({ person, result }); 

pureAssocGibt jetzt ein testbares Ergebnis zurück und wir werden uns keine Sorgen machen, wenn es irgendwo anders leise etwas mutiert.

Sie könnten sogar Folgendes tun und rein bleiben:

Ein anderer reiner Weg

const pureAssoc = (key, value, object) => { const newObject = { ...object }; newObject[key] = value; return newObject; }; const person = { name: 'Bobo' }; const result = pureAssoc('shoeSize', 400, person); console.log({ person, result }); 

Das Mutieren Ihrer Eingabe kann gefährlich sein, aber das Mutieren einer Kopie davon ist kein Problem. Unser Endergebnis ist immer noch eine überprüfbare, vorhersehbare Funktion, die unabhängig davon funktioniert, wo und wann Sie sie aufrufen.

Die Mutation ist auf diesen kleinen Bereich beschränkt und Sie geben immer noch einen Wert zurück.

Deep-Cloning-Objekte

Kopf hoch! Mit dem Spread-Operator ...wird eine flache Kopie eines Objekts erstellt. Flache Kopien sind vor verschachtelten Mutationen nicht sicher.

Vielen Dank an Rodrigo Fernández Díaz, der mich darauf aufmerksam gemacht hat!

Unsichere verschachtelte Mutation

const person = { name: 'Bobo', address: { street: 'Main Street', number: 123 } }; const shallowPersonClone = { ...person }; shallowPersonClone.address.number = 456; console.log({ person, shallowPersonClone }); 

Beide personund shallowPersonClonewurden mutiert, weil ihre Kinder die gleiche Referenz teilen!

Sichere verschachtelte Mutation

To safely mutate nested properties, we need a deep clone.

const person = { name: 'Bobo', address: { street: 'Main Street', number: 123 } }; const deepPersonClone = JSON.parse(JSON.stringify(person)); deepPersonClone.address.number = 456; console.log({ person, deepPersonClone }); 

Now you’re guaranteed safety because they’re truly two separate entities!

Summary

  • A function’s pure if it’s free from side-effects and returns the same output, given the same input.
  • Side-effects include: mutating input, HTTP calls, writing to disk, printing to the screen.
  • You can safely clone, thenmutate, your input. Just leave the original one untouched.
  • Spread syntax ( syntax) is the easiest way to shallowly clone objects.
  • JSON.parse(JSON.stringify(object)) is the easiest way to deeply clone objects. Thanks again Rodrigo Fernández Díaz!

My Free Course

This tutorial was from my completely free course on Educative.io, Functional Programming Patterns With RamdaJS!

Please consider taking/sharing it if you enjoyed this content.

It’s full of lessons, graphics, exercises, and runnable code samples to teach you a basic functional programming style using RamdaJS.

Thanks for reading! Until next time.