Състоянието в JavaScript се обяснява с приготвянето на обикновено ястие

Ако някога сте приготвяли ястие у дома, тогава можете да разберете как да пишете код с състояние, като използвате обектно-ориентирани методи за програмиране в JavaScript.

Когато започнете да пишете прости програми на JavaScript, не е нужно да се притеснявате от броя на променливите, които използвате или как различните функции и обекти работят заедно.

Например, повечето хора започват с използване на много глобални променливи или променливи, които са обхванати в горното ниво на файла. Те не са част от отделен клас, обект или функция.

Например, това е глобална променлива, наречена състояние :

let state = "global";

Но след като вашата програма започне да включва много различни функции и / или обекти, ще трябва да създадете по-строг набор от правила за вашия код.

Тук влиза в действие понятието държава. State описва състоянието на цялата програма или на отделен обект. Това може да бъде текст, число, булева стойност или друг тип данни.

Това е често срещан инструмент за координиране на код. Например, след като актуализирате състоянието, куп различни функции могат незабавно да реагират на тази промяна.

Тази статия описва състоянието в контекста на React, популярна JavaScript библиотека.

Но познайте какво? Дори държавата може да ви боли в главата, след като кодът ви се усложни! Промяната на състоянието може да доведе до непредвидени последици.

Да спрем точно там. Държавата е популярен инструмент в обектно-ориентираното програмиране или ООП. Но много програмисти предпочитат функционалното програмиране, което обезкуражава промените в състоянието. JavaScript поддържа и двете парадигми.

Добре, това е много терминология наведнъж. Исках да намеря начин да покажа как ООП и функционалното програмиране могат да постигнат едни и същи цели, дори ако функционалното програмиране не използва състояние.

Този урок ще покаже как можете да приготвите ястие от спагети и сос от ООП и функционална перспектива.

Ето бърз преглед на двата различни подхода:

Нека да скочим в него. За да разберете този урок, просто трябва да разберете функции и обекти в JavaScript.

Обектно-ориентиран метод (използване на състояние)

На графиката по-горе показахме два различни подхода за приготвяне на тази паста за вечеря:

  1. Метод, който се фокусира върху състоянието на различните инструменти, като печката, тенджерата и тестените изделия.
  2. Метод, който е фокусиран върху развитието на самата храна, без да се споменава състоянието на отделните инструменти (тенджери, печки и др.)

Обектно-ориентираният подход се фокусира върху актуализиране на състоянието, така че нашият код ще има състояние на две различни нива:

  1. Глобално, или състоянието на цялото това хранене.
  2. Локално за всеки обект.

Ще използваме синтаксис ES6 в този урок за създаване на обекти. Ето пример за глобално състояние и прототипа „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'; }

Забележка: Опростих console.logизявлението, за да се съсредоточа върху актуализацията на състоянието.

Ето визуално представяне на тази логика:

Преди

След

Има две състояния и когато pastaPotе създаден чрез Potпрототипа, той първоначално има празно boilStatus. Но след това има промяна в държавата.

Тичаме pastaPot.startBoiling()и сега boilStatus(местната държава) „кипи“, тъй като глобалното състояние на stoveTempе над 400.

А сега да отидем една стъпка по-напред. Ще позволим на макароните да се сварят поради състоянието на pastaPot.

Ето кода, който ще добавим към горния фрагмент:

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

Уау! Това е много наведнъж. Ето какво се случи.

  1. Създадохме нов прототип на „Паста“, където всеки обект ще има локално състояние, наречено cookedStatus
  2. Създадохме нов екземпляр на паста, наречен myMeal
  3. Ние използвахме държавата от pastaPotобекта, който създадохме в последния фрагмент, за да се определи дали трябва да се актуализира състоянието, наречено cookedStatusв myMealза варени.
  4. Тъй като състоянието на boilStatusин pastaPotбеше „вряло“, нашите макарони вече са сготвени!

Ето този процес визуално:

Преди

След

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.