Search  
Always will be ready notify the world about expectations as easy as possible: job change page
27 августа 2020 г.

«Чистые» и «нечистые» функции в JavaScript

Author:
Alex Myzgin
Source:
Views:
1263

«Чистые» функции - это любые функции, исходные данные которых получены исключительно из их входных данных и не вызывают побочных эффектов в приложении. Математические функции являются примерами «чистых» функций. «Нечистые» функции бывают разных форм и размеров. Вот некоторые примеры:

  • функции, вывод которых зависит от внешнего / глобального состояния;
  • функции, которые возвращают разные исходные данные при одинаковых входных;
  • функции, которые изменяют состояние приложения;
  • функции, которые изменяют «внешний мир».

Функциональное программирование основано на использовании «чистых» функций и строгом контроле побочных эффектов. Способность распознавать любой тип функции является ключевым для функционального программирования.

«Чистая» функция - это функция, которая выводит свои данные основываясь исключительно на свои входные данные и не вызывает побочных эффектов в приложении.

Например у нас есть функция, которая получает одно значение x и возвращает в данном случае x + 1:

// function f(x) { return x + 1 }

const f = x => x + 1;

Довольно легко понять, что это «чистая» функция. Мы получаем тот же результат при вызове этой функции, с тем же входным значением; плюс у нас нет внешних зависимостей, которые бы вызывали побочные эффекты. Чтобы понять это далее, давай сравним это с несколькими «нечистыми» функциями.

Первая «нечистая» функция

Первая «нечистая» функция, которую мы собираемся сделать - это та, чей результат не основан исключительно на её входных данных. Например, давай рассмотрим функцию totalPrice. У нас есть глобальная переменная COST_OF_ITEM, которая содержит цену на товар. Функция totalPrice берет quantity и умножает ее на эту переменную.

// Глобальная переменная

const COST_OF_ITEM = 250;

const totalPrice = quantity => COST_OF_ITEM * quantity;

На первый взгляд может показаться, что это «чистая» функция, потому что мы всегда получаем один и тот же результат на основе одного и того же входного значения. Это можно увидеть, вызвав её несколько раз с одним и тем же значением, и вызвав в консоль. В обоих случаях мы получаем 500.

// Глобальная переменная

const COST_OF_ITEM = 250;

const totalPrice = quantity => COST_OF_ITEM * quantity;

console.log(totalPrice(2)); // 500
console.log(totalPrice(2)); // 500

Хоть мы и получаем тот же результат, но это «нечистая» функция, так как состояние нашего приложения влияет на вывод нашей функции. Мы можем увидеть это, изменив значение COST_OF_ITEM и посмотреть снова в консоль.

const COST_OF_ITEM = 200;

const totalPrice = quantity => COST_OF_ITEM * quantity;

console.log(totalPrice(2)); // 400
console.log(totalPrice(2)); // 400

Вторая «нечистая» функция

Наш второй пример «нечистой» функции - это функция, которая получает один и тот же аргумент, но возвращает разные результаты. Часто в наших приложениях нам нужно создавать объекты, которые имеют уникальные идентификаторы, такие как id.

Давай создадим функцию generateID. Эта функция будет возвращать целое число в случайном порядке. Это «нечистая» функция, так как вызвав её несколько раз, каждый раз мы получим разный результат.

const generateID = () => Math.floor(Math.random() * 10000);

console.log(generateID()); // 7602
console.log(generateID()); // 1377
console.log(generateID()); // 7131

Давай используем нашу «нечистую» функцию generateID внутри фабричной функции для создания пользовательских объектов. Чтобы создать пользователя, createUser принимает два параметра: name и age, и возвращает объект с id, используя функцию generateID для его создания, а также name и age.

const generateID = () => Math.floor(Math.random() * 10000);

const createUser = (name, age) => ({
id: generateID(),
name,
age
});

Вызовем createUser несколько раз, с одинаковыми аргументами.

const generateID = () => Math.floor(Math.random() * 10000);

const createUser = (name, age) => ({
id: generateID(),
name,
age
});
console.log(createUser("Alex", 28)); // {id: 3141, name: "Alex", age: 28}
console.log(createUser("Alex", 28)); // {id: 9646, name: "Alex", age: 28}
console.log(createUser("Alex", 28)); // {id: 9218, name: "Alex", age: 28}

Если посмотрим в консоль, то увидим, что мы получили похожие объекты, но они не одинаковые - id у всех разный.

«Нечистота» функции generateID делает нашу фабричную функцию createUser «нечистой». Для того чтобы исправить это - можно переместить «нечистую» функцию за пределы фабрики и вызвать её где-нибудь, где мы ожидаем побочный эффект, и передать id в качестве параметра в нашу фабрику createUser.

Третья «нечистая» функция

Третий пример. Как и в примере с глобальной переменной, мы можем создавать функции, которые изменяют состояние нашего приложения, вызывая побочный эффект.

Допустим, мы отслеживаем изменяемое значение (в данном случае id). Если мы создадим функцию, которая изменяет это значение, у нас будет «нечистая» функция. Например фабричная функция createPersone.

let id = 0;

const createPersone = name => ({
id: ++id,
name
});

Если мы генерируем наш id для этого объекта, изменяя значение глобального id, то это «нечистая» функция. Вызвав эту функции несколько раз с разными name, то увидим, что id увеличился как мы и ожидали, но если мы также выведем в консоль глобальное значение id, то увидим, что оно тоже изменилось.

let id = 0;

const createPersone = name => ({
id: ++id,
name
});

console.log(createPersone("Alex")); // {id: 1, name: "Alex"}
console.log(createPersone("Julia")); // {id: 2, name: "Julia"}
console.log(id); // 2

Четвертая «нечистая» функция

Последний четвертый пример «нечистой» функции - это побочный эффект “внешнего мира”. console.log - «нечистая» функция, так как она создает побочный эффект во “внешнем мире”.

Каждый раз, когда мы используем console.log, это влияет на нашу консоль, а это побочный эффект. Если у нас есть какая-либо функция, использующая console.log, (например, функция logger, которая принимает сообщение и выводит его) это тоже «нечистая» функция.

const logger = msg => {
console.log(msg);
};

logger("Всем привет!"); 

Similar
Aug 15
The JavaScript fetch() method is used to fetch resources from a server. It returns a Promise that resolves to the Response object representing the response to the request. The fetch method can also make HTTP requests - GET request (to...
3 weeks ago
Author: Dante J. Anjos
In this post I want to show how we can easily create a modal with vanilla JavaScript. It can have multiple open/close handlers thanks to querySelectorAll. First of all lets create the HTML structure for our modal. <div class="modal">  ...
30 октября
Автор: Дмитрий Брайт
JS-библиотеку htmx воспринимают как средство, которое спасает интернет от одностраничных приложений. Всё дело в том, что React поглотил разработчиков своей сложностью (так говорят), а htmx предлагает столь желанное спасение. Создатель htmx, Карсон Гросс, иронично объясняет эту динамику библиотеки так: Нет,...
Aug 28
Author: Tushar Kanjariya
Step-by-step guide to creating custom context menus (right-click menu) in JavaScript. Hello Developers 👋, A context menu, also known as a right-click menu or pop-up menu, is a menu that appears when the user performs a specific action, such as...
Send message
Type
Email
Your name
*Message