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

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

Автор:
Alex Myzgin
Источник:
Просмотров:
1238

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

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

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

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

Например у нас есть функция, которая получает одно значение 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("Всем привет!"); 

Похожее
24 марта
Автор: Ivan Kolesov
Фреймворк Angular используется при создании SPA и предлагает большое количество инструментов как для создания, непосредственно, элементов интерфейса, так и CLI для создания и управления структурой файлов, относящихся к приложению. Для создания проекта с использованием библиотеки Angular, официальный сайт предлагает нам...
Feb 3, 2022
Author: Satish Chandra Gupta
What if programming languages were stocks? And you had to make a portfolio to fetch good returns in 2022? You probably have seen various surveys and analyses listing the most popular programming languages. Those cover the universe of programming languages,...
Feb 26, 2023
Author: Ian Segers
Error handling with Async/Await in JS This will be a small article, based on some issues I picked up during code reviews and discussions with other developers. This article is rather focused on the novice JS developers. A Simple Try...
27 мая
Автор: Марина Александровна
Уверены, что вопросы на собеседовании frontend — настоящая боль? Мы взяли на себя поиск наиболее популярных и дали на них развёрнутые ответы. Казалось бы, вопросы на собеседовании frontend разработчика Junior не должны отличаться от стандартных задачек с IT-сайтов. Даже мы...
Написать сообщение
Тип
Почта
Имя
*Сообщение