Стан у JavaScript пояснюється приготуванням простої їжі

Якщо ви коли-небудь готували їжу вдома, то ви можете зрозуміти, як писати код з використанням об'єктів, використовуючи об'єктно-орієнтовані методи програмування в JavaScript.

Коли ви починаєте писати прості програми JavaScript, вам не потрібно турбуватися про кількість змінних, які ви використовуєте, або про те, як різні функції та об'єкти працюють разом.

Наприклад, більшість людей починають з використанням великої кількості глобальних змінних або змінних, які мають масштаб на верхньому рівні файлу. Вони не входять до жодного окремого класу, об'єкта чи функції.

Наприклад, це глобальна змінна, яка називається state :

let state = "global";

Але як тільки ваша програма почне залучати багато різних функцій та / або об'єктів, вам потрібно буде створити більш суворий набір правил для вашого коду.

Тут і вступає в силу поняття держави. Стан описує статус всієї програми або окремого об'єкта. Це може бути текст, число, логічне значення або інший тип даних.

Це загальний інструмент для координації коду. Наприклад, як тільки ви оновите стан, купа різних функцій може миттєво відреагувати на цю зміну.

У цій статті описано стан у контексті популярної бібліотеки JavaScript React.

Але вгадайте що? Навіть штат може завдати вам головного болю, як тільки ваш код ускладниться! Зміна стану може спричинити непередбачені наслідки.

Зупинимось тут же. State - це популярний інструмент в об'єктно-орієнтованому програмуванні, або ООП. Але багато програмістів віддають перевагу функціональному програмуванню, яке знеохочує зміни стану. JavaScript підтримує обидві парадигми.

Гаразд, це багато термінології відразу. Я хотів знайти спосіб показати, як ООП і функціональне програмування можуть досягти тих самих цілей, навіть якщо функціональне програмування не використовує стан.

Цей підручник покаже, як ви можете приготувати їжу зі спагетті та соусу з ООП та функціональної точки зору.

Ось короткий попередній перегляд двох різних підходів:

Давайте стрибнемо в нього. Для того, щоб зрозуміти цей посібник, вам просто потрібно зрозуміти функції та об'єкти в JavaScript.

Об'єктно-орієнтований метод (з використанням стану)

На графіку вище ми показали два різні підходи до приготування цієї макаронної вечері:

  1. Метод, орієнтований на стан різних інструментів, таких як плита, каструля та макарони.
  2. Метод, орієнтований на прогресування самої їжі, без згадування стану окремих інструментів (каструль, печей тощо)

Об'єктно-орієнтований підхід фокусується на оновленні стану, тому наш код матиме стан на двох різних рівнях:

  1. Глобальний, або стан усієї цієї їжі.
  2. Місцевий для кожного об’єкта.

У цьому посібнику ми збираємось використовувати синтаксис ES6 для створення об’єктів. Ось приклад глобальної держави та прототип “Горщика”.

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.