Zustand in JavaScript erklärt durch Kochen einer einfachen Mahlzeit

Wenn Sie jemals zu Hause eine Mahlzeit gekocht haben, können Sie verstehen, wie Sie mithilfe objektorientierter Programmiermethoden in JavaScript statusbehafteten Code schreiben.

Wenn Sie mit dem Schreiben einfacher JavaScript-Programme beginnen, müssen Sie sich keine Gedanken über die Anzahl der verwendeten Variablen oder die Zusammenarbeit verschiedener Funktionen und Objekte machen.

Beispielsweise verwenden die meisten Benutzer zunächst viele globale Variablen oder Variablen, die sich auf der obersten Ebene der Datei befinden. Sie sind nicht Teil einer einzelnen Klasse, eines Objekts oder einer Funktion.

Dies ist beispielsweise eine globale Variable namens state :

let state = "global";

Sobald Ihr Programm jedoch viele verschiedene Funktionen und / oder Objekte umfasst, müssen Sie strengere Regeln für Ihren Code erstellen.

Hier kommt der Staatsbegriff ins Spiel. Status beschreibt den Status des gesamten Programms oder eines einzelnen Objekts. Dies kann Text, eine Zahl, ein Boolescher Wert oder ein anderer Datentyp sein.

Es ist ein gängiges Werkzeug zur Koordinierung von Code. Wenn Sie beispielsweise den Status aktualisieren, können eine Reihe verschiedener Funktionen sofort auf diese Änderung reagieren.

Dieser Artikel beschreibt den Status im Kontext von React, einer beliebten JavaScript-Bibliothek.

Aber rate mal was? Selbst der Zustand kann Ihnen Kopfschmerzen bereiten, sobald Ihr Code kompliziert wird! Eine Änderung des Zustands kann unbeabsichtigte Folgen haben.

Hören wir gleich dort auf. State ist ein beliebtes Werkzeug in der objektorientierten Programmierung (OOP). Viele Programmierer bevorzugen jedoch eine funktionale Programmierung, die von Zustandsänderungen abhält. JavaScript unterstützt beide Paradigmen.

Okay, das ist eine Menge Terminologie auf einmal. Ich wollte einen Weg finden, um zu zeigen, wie OOP und funktionale Programmierung dieselben Ziele erreichen können, auch wenn die funktionale Programmierung keinen Status verwendet.

Dieses Tutorial zeigt, wie Sie eine Mahlzeit aus Spaghetti und Sauce aus OOP- und funktionaler Sicht zubereiten können.

Hier ist eine kurze Vorschau der beiden verschiedenen Ansätze:

Lass uns hineinspringen. Um dieses Tutorial zu verstehen, müssen Sie nur Funktionen und Objekte in JavaScript verstehen.

Objektorientierte Methode (Verwenden des Status)

In der obigen Grafik haben wir zwei verschiedene Ansätze gezeigt, um dieses Pastadinner zuzubereiten:

  1. Eine Methode, die sich auf den Zustand der verschiedenen Werkzeuge wie Herd, Topf und Nudeln konzentriert.
  2. Eine Methode, die sich auf das Fortschreiten des Lebensmittels selbst konzentriert, ohne den Zustand der einzelnen Werkzeuge (Töpfe, Öfen usw.) zu erwähnen.

Der objektorientierte Ansatz konzentriert sich auf die Aktualisierung des Status, sodass unser Code einen Status auf zwei verschiedenen Ebenen hat:

  1. Global oder der Zustand dieser gesamten Mahlzeit.
  2. Lokal für jedes Objekt.

In diesem Lernprogramm wird die ES6-Syntax zum Erstellen von Objekten verwendet. Hier ist ein Beispiel für den globalen Zustand und den Prototyp „Pot“.

let stoveTemp = 500;
function Pot(){ this.boilStatus = ''; this.startBoiling = function(){ if( stoveTemp > 400) this.boilStatus = "boiling"; }}
let pastaPot = new Pot();pastaPot.startBoiling();
console.log(pastaPot);// Pot { boilStatus = 'boiling'; }

Hinweis: Ich habe die console.logAnweisung vereinfacht, um mich auf die Statusaktualisierung zu konzentrieren.

Hier ist eine visuelle Darstellung dieser Logik:

Vor

Nach

Es gibt zwei Zustände, und wenn der pastaPotüber den PotPrototyp erstellt wird, ist er zunächst leer boilStatus. Aber dann gibt es eine Zustandsänderung.

Wir rennen pastaPot.startBoiling(), und jetzt boilStatus„kocht“ der (lokale Staat), da der globale Staat stoveTempüber 400 liegt.

Gehen wir jetzt noch einen Schritt weiter. Wir werden zulassen, dass die Nudeln aufgrund des Zustands von gekocht werden pastaPot.

Hier ist der Code, den wir dem obigen Snippet hinzufügen werden:

function Pasta (){ this.cookedStatus = false; this.addToPot = function (boilStatus){ if(boilStatus == "boiling") this.cookedStatus = true; }}
let myMeal = new Pasta();myMeal.addToPot(pastaPot.boilStatus);
console.log(myMeal.cookedStatus);// true

Woah! Das ist viel auf einmal. Folgendes ist passiert.

  1. Wir haben einen neuen Prototyp von „Pasta“ erstellt, bei dem jedes Objekt einen lokalen Status hat cookedStatus
  2. Wir haben eine neue Instanz von Pasta namens erstellt myMeal
  3. Wir benutzten den Zustand von dem pastaPotObjekt , das wir in dem letzten Schnipsel erstellt , um zu bestimmen , ob wir den Zustand genannt aktualisieren sollen cookedStatusin myMealgekocht.
  4. Da der Zustand von boilStatusin pastaPot"kochte", ist unsere Pasta jetzt gekocht!

Hier ist dieser Prozess visuell:

Vor

Nach

So, we now have the local state of one object, that depends on the local state of another object. And that local state depended on some global state! You can see how this can be challenging. But, it is at least easy to follow for now, since states are updated explicitly.

Functional Method (without state)

In order to fully understand state, you should be able to find a way to accomplish the same outcome as the code above without actually modifying state. This is where functional programming helps!

Functional programming has two core values that separate it from OOP: immutability and pure functions.

I am not going to go into too much depth on those topics, but if you want to learn more, I encourage you to check out this guide to functional programming in JavaScript.

Both of these principles discourage the use of state modification in your code. That means that we can’t use local or global state.

Functional programming instead encourages us to pass in parameters to individual functions. We can use outside variables, but we can’t use them as state.

Here’s an example of a function that will boil the pasta:

const stoveTemp = 500;
const cookPasta = (temp) => { if(temp > 400) return 'cooked';}
console.log(cookPasta(stoveTemp));// 'cooked'

This code will successfully return a string of ‘cooked’. But notice — there is no object that we are updating. The function simply returns the value that will be used in the next step.

Instead, we are focused on the inputs and outputs of one function: cookPasta.

This perspective looks at the transformation of the food itself, rather than the tools that are used to cook it. It’s a little harder to visualize, but we don’t need to have the function depend on external state.

Here’s what it looks like:

Think of it as a “timeline view” for the progress of the meal — this particular function just covers the first part, the transition from dry pasta to cooked pasta.

Now let’s cover the second part as the food is served. Here’s the code that will serve the meal. It will come after the code block above:

const serveMeal = (pasta) => { if (pasta == 'cooked') return 'Dinner is ready.'}
console.log( serveMeal(cookPasta(stoveTemp)) );// 'Dinner is ready.'

Now, we are delivering the results of the cookPasta function directly into the serveMeal function. Again, we are able to do this without changing state, or changing data structures.

Here’s a diagram that uses the “timeline view” to show how these two functions work together:

Interested In More Visual Tutorials?

If you enjoyed this guide, give it a “clap”!

And, if you would like to read more visual tutorials about HTML, CSS and JavaScript, check out the main CodeAnalogies site for 50+ tutorials.