Функциональное программирование в последние годы привлекло большое внимание в мире Javascript. Собеседования со старшим разработчиком Javascript требуют понимания чистых функций, побочных эффектов функции, избегания общего состояния и т. Д. Если эти темы вам чужды или вы, возможно, слышали об этом от своих коллег, но не совсем уверены в том, что означает каждая тема. Тогда эта статья для вас. Я начну эту статью о функциональном программировании с вопроса ПОЧЕМУ, затем перейду к ЧТО и, в конце концов, к КАК.

ПОЧЕМУ функциональное программирование

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

Позвольте мне привести пример, который объяснит вам, почему функциональное программирование - это круто.

var obj = {
  a: 10
};
func1();
console.log(obj.a);   // First 
func2();
console.log(obj.a);   // Second
func3(obj);
console.log(obj.a);   // Third

Теперь, не зная, что находится внутри функций func1, func2 и func3, насколько вы уверены в значении obj.a в первом, втором и третьем журналах, не так ли? Верно!. Что, если я скажу вам, что этот код соответствует подходу функционального программирования, тогда вы можете быть на 100% уверены, что значение, напечатанное на консоли, будет 10 во всех случаях. В этом сила функционального программирования.

ЧТО такое функциональное программирование

Перейдем к ЧТО. Я не буду слишком подробно останавливаться на определении функционального программирования, поскольку мы рассмотрим большинство вещей в определении позже в этой статье. Функциональное программирование - это парадигма программирования, в которой мы пишем наше приложение с использованием чистых, детерминированных функций, избегая побочных эффектов и общего состояния. Это скорее декларативный, чем императивный характер. Я знаю, что определение может быть немного сложнее для понимания, я постараюсь упростить и объяснить это более подробно.

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

Чистые функции

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

Возможные побочные эффекты

  1. Изменение глобального значения (переменной, свойства или структуры данных)
  2. Изменение исходного значения аргумента функции.
  3. Выбрасывание исключения
  4. Печать на экран или ведение журнала.
  5. Вызов других функций, имеющих побочные эффекты.

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

Избегайте общего состояния

Что такое государство? Программа считается с сохранением состояния, если она предназначена для запоминания данных о событиях или взаимодействиях с пользователем, запомненная информация называется состоянием программы. Поскольку Javascript хранит данные (состояние) в переменных и объектах, когда конкретный объект передается и изменяется в разных областях, мы разделяем состояние. И этого нужно избегать. Общая область может включать глобальную область или область закрытия.

// Consider below two function foo and bar
// foo is modifying the outer scope variable 
const obj1 = {
  name: 'Jack'
}
const foo = (newName) => {
  obj1.name = newName;
}
const bar = (oldObj, newName) {
  return Object.assign({}, oldObj, { name: newName });
}
foo('John'); // This will modify our shared state which obj1
bar(obj1, 'Rachel'); 
// This will not modify our shared state, instead it will 
// return a brand new object with updated name for us to start using // this new object. We must write functions following the same idea // of not changing the outer scope objects instead returning new 
// object with updated value

Избегайте мутации данных

Функциональное программирование стремится к неизменности. Если объект данных может быть изменен из нескольких мест в коде, то этим объектом очень трудно управлять и прогнозировать его значение. С помощью функционального программирования мы хотим быть полностью уверены в ценности объекта в любой конкретный момент, чтобы облегчить нашу жизнь как разработчика. Вот почему неизменность - один из основных принципов функционального программирования. Для создания неизменяемых объектов Javascript предоставляет различные методы, такие как Object.freeze (), Object.defineProperties (). Эти функции обеспечивают неизменяемость объекта. Вы можете прочитать другие блоги, чтобы получить более подробную информацию о том, как добиться неизменности в Javascript.

Функции первого класса

Функции обрабатываются как значения. В Javascript функции могут использоваться как значение, как строковое или числовое значение. Это означает, что все нижеприведенные случаи функций действительны.

  1. var func1 = function () {...};
  2. var arr = [28, функция () {...}];
  3. var obj = {число: 28, func2: function () {…}}
  4. func3 (10, функция () {…})
  5. function func4 () {return function () {…}}

Функции высшего порядка

Функции высшего порядка - это функции, которые работают с другими функциями, либо принимая их в качестве аргументов, либо возвращая их. Тот факт, что Javascript поддерживает функции первого класса, позволяет создавать функции высшего порядка. Если вы увидите пункты 4 и 5 в приведенной выше теме, вы заметите, что func3 и func4 являются функциями высшего порядка.

Если вы использовали функции map (), filter () или reduce () для массивов, вы поймете, что это функции высшего порядка. Эти функции широко используются в функциональном программировании на Javascript. Они декларативны по сравнению с использованием традиционного подхода, такого как цикл for, и генерируют новое значение при каждом вызове, что означает, что он не изменяет исходный объект Array. Я предлагаю вам прочитать об этих функциях, если вы не знаете больше о функциональном программировании на Javascript.

Состав функций

Функции в функциональном программировании имеют следующие атрибуты
1. Функции имеют вход.
2. Функции возвращают значение.
3. Функции упрощены до одной задачи.

Поскольку функция выполняет одну более простую задачу, вам нужно будет объединить несколько функций вместе, чтобы выполнить более крупную и сложную задачу. Это называется функциональной композицией. Композиция функций объединяет несколько функций с целью создания новой функции для выполнения сложной задачи.
По мере того, как мы переходим от функции, выполняющей несколько задач со сложной логикой, к нескольким функциям, выполняющим одну работу с простой логикой, мы можем повторно использовать функции легко, такая практика кодирования увеличивает возможность повторного использования кода.

Теперь мы можем выполнить композицию функций, как показано ниже.

filerArr(spliVal(capitalize(trunc(str))))

Но приведенный выше код сложно не только читать, но и писать.
Чтобы решить эту проблему, Javascript дает нам возможность сделать код доступным для чтения и записи. Мы можем реализовать наши собственные функции compose () и pipe () для композиции функций.

const compose = function (...fns) {
  return function(x) {
    return fns.reduceRight(function(v, f) {
      return f(v),
    }, x)
  }
}
// pipe function is similar to compose but it uses reduce function
// You don't have to get into the understanding of compose and //reduce functions right now as they are beyond the scope of this //article
const prepareString = compose(
  filterArray,
  splitVal,
  capitalize,
  trunc
);
console.log(prepareString(str))

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

Функции карри

Поскольку reduce () и reduceRight () передают только один аргумент функции, мы можем использовать указанную выше функцию compose только для тех функций, которые принимают 1 аргумент. Это проблема. Как мы обрабатываем функции, которые принимают более 1 аргумента. Вот один из вариантов использования функций карри. Используя функции карри, мы всегда применяем к функции один аргумент за раз.

Функции Карри преобразуют функцию с арностью больше 1 в последовательность функций с аргументом 1. Рассмотрим пример.

// This is a function which accepts more than 1 argument
const add = (a, b) {
  return a + b;
}
// now if we want to apply the arguments to the above function one // at a time then we would be need curry function
const curriedAdd = curry(add);
// Now we can pass arguments to curriedAdd() one at time, each time // a function is returned until all the arguments required by add /// have been passed. At the end final value will be returned by //applying all the arguments.
curriedAdd(2)(3) // output will be 5
// How to use curriedAdd in function composition
compose(
  curriedAdd(2),
  getUserInput
)
// Here We have applied 2 as first argument to add and last argument // will be the returned value from getUserInput

Примечание. Этот пример можно использовать только тогда, когда последний аргумент функции ожидается из значения, возвращенного предыдущей функцией в составе функции.
В случае, если нам нужно передать значение в любом другом месте, вы можете использовать следующую технику .

compose(
  (x) => curriedAdd(x)(2),
  getUserInput
)

Это всего лишь краткое введение в концепции функционального программирования на Javascript. Здесь есть чему поучиться. Я предлагаю вам ознакомиться со статьями, опубликованными Эриком Эллиоттом по функциональному программированию, чтобы получить больше знаний.



Овладейте собеседованием на JavaScript: что такое функциональное программирование?
« Освойте собеседование на JavaScript
- это серия сообщений, предназначенных для подготовки кандидатов к ответам на общие вопросы… medium.com »





Карри и функциональная композиция
Примечание. Это часть серии« Программное обеспечение для создания текста
, посвященной изучению функционального программирования и композиционного программного обеспечения… medium.com»