Поиск…
замечания
Что такое функциональное программирование?
Функциональное программирование или FP - это парадигма программирования, основанная на двух основных понятиях неизменности и безгражданства . Цель FP - сделать ваш код более читаемым, многоразовым и переносимым.
Что такое функциональный JavaScript
Прозвучала дискуссия о том, чтобы назвать JavaScript функциональным языком или нет. Однако мы можем абсолютно использовать JavaScript как функциональный по своей природе:
- Имеет чистые функции
- Имеет функции первого класса
- Имеет функцию более высокого порядка
- Он поддерживает неизменность
- Имеет закрытие
- Рекурсия и методы переадресации списков (массивы), такие как map, reduce, filter..etc
Примеры должны подробно описывать каждую концепцию, а ссылки, приведенные здесь, предназначены только для справки и должны быть удалены после иллюстрации концепции.
Принятие функций в качестве аргументов
function transform(fn, arr) {
let result = [];
for (let el of arr) {
result.push(fn(el)); // We push the result of the transformed item to result
}
return result;
}
console.log(transform(x => x * 2, [1,2,3,4])); // [2, 4, 6, 8]
Как вы можете видеть, наша функция transform
принимает два параметра, функцию и коллекцию. Затем он перебирает коллекцию и передает значения на результат, вызывая fn
для каждого из них.
Выглядит знакомо? Это очень похоже на то, как работает Array.prototype.map()
!
console.log([1, 2, 3, 4].map(x => x * 2)); // [2, 4, 6, 8]
Функции более высокого порядка
В общем, функции, которые работают с другими функциями, либо путем принятия их в качестве аргументов, либо путем их возврата (или обоих), называются функциями более высокого порядка.
Функция более высокого порядка - это функция, которая может принимать другую функцию в качестве аргумента. Вы используете функции более высокого порядка при передаче обратных вызовов.
function iAmCallbackFunction() {
console.log("callback has been invoked");
}
function iAmJustFunction(callbackFn) {
// do some stuff ...
// invoke the callback function.
callbackFn();
}
// invoke your higher-order function with a callback function.
iAmJustFunction(iAmCallbackFunction);
Функция более высокого порядка также является функцией, которая возвращает в качестве результата другую функцию.
function iAmJustFunction() {
// do some stuff ...
// return a function.
return function iAmReturnedFunction() {
console.log("returned function has been invoked");
}
}
// invoke your higher-order function and its returned function.
iAmJustFunction()();
Идентичность Монады
Это пример реализации идентичной монады в JavaScript и может служить отправной точкой для создания других монадов.
Основываясь на конференции Дугласа Крокфорда о монадах и гонадах
Используя этот подход, повторное использование ваших функций будет проще благодаря гибкости, предоставляемой этой монадой, и составлению кошмаров:
f(g(h(i(j(k(value), j1), i2), h1, h2), g1, g2), f1, f2)
читаемый, красивый и чистый:
identityMonad(value)
.bind(k)
.bind(j, j1, j2)
.bind(i, i2)
.bind(h, h1, h2)
.bind(g, g1, g2)
.bind(f, f1, f2);
function identityMonad(value) {
var monad = Object.create(null);
// func should return a monad
monad.bind = function (func, ...args) {
return func(value, ...args);
};
// whatever func does, we get our monad back
monad.call = function (func, ...args) {
func(value, ...args);
return identityMonad(value);
};
// func doesn't have to know anything about monads
monad.apply = function (func, ...args) {
return identityMonad(func(value, ...args));
};
// Get the value wrapped in this monad
monad.value = function () {
return value;
};
return monad;
};
Он работает с примитивными значениями
var value = 'foo',
f = x => x + ' changed',
g = x => x + ' again';
identityMonad(value)
.apply(f)
.apply(g)
.bind(alert); // Alerts 'foo changed again'
А также с объектами
var value = { foo: 'foo' },
f = x => identityMonad(Object.assign(x, { foo: 'bar' })),
g = x => Object.assign(x, { bar: 'foo' }),
h = x => console.log('foo: ' + x.foo + ', bar: ' + x.bar);
identityMonad(value)
.bind(f)
.apply(g)
.bind(h); // Logs 'foo: bar, bar: foo'
Давайте попробуем все:
var add = (x, ...args) => x + args.reduce((r, n) => r + n, 0),
multiply = (x, ...args) => x * args.reduce((r, n) => r * n, 1),
divideMonad = (x, ...args) => identityMonad(x / multiply(...args)),
log = x => console.log(x),
substract = (x, ...args) => x - add(...args);
identityMonad(100)
.apply(add, 10, 29, 13)
.apply(multiply, 2)
.bind(divideMonad, 2)
.apply(substract, 67, 34)
.apply(multiply, 1239)
.bind(divideMonad, 20, 54, 2)
.apply(Math.round)
.call(log); // Logs 29
Чистые функции
Основным принципом функционального программирования является то, что он позволяет избежать изменения состояния приложения (безгражданства) и переменных вне его (неизменяемости).
Чистые функции - это функции, которые:
- с заданным входом, всегда возвращают один и тот же выход
- они не полагаются на какую-либо переменную за пределами их возможностей
- они не изменяют состояние приложения ( без побочных эффектов )
Давайте рассмотрим несколько примеров:
Чистые функции не должны изменять какую-либо переменную за пределами их возможностей
Нечистая функция
let obj = { a: 0 }
const impure = (input) => {
// Modifies input.a
input.a = input.a + 1;
return input.a;
}
let b = impure(obj)
console.log(obj) // Logs { "a": 1 }
console.log(b) // Logs 1
Функция изменила значение obj.a
которое находится за пределами его области.
Чистая функция
let obj = { a: 0 }
const pure = (input) => {
// Does not modify obj
let output = input.a + 1;
return output;
}
let b = pure(obj)
console.log(obj) // Logs { "a": 0 }
console.log(b) // Logs 1
Функция не меняла значения объекта obj
Чистые функции не должны полагаться на переменные за пределами их возможностей
Нечистая функция
let a = 1;
let impure = (input) => {
// Multiply with variable outside function scope
let output = input * a;
return output;
}
console.log(impure(2)) // Logs 2
a++; // a becomes equal to 2
console.log(impure(2)) // Logs 4
Эта нечистая функция зависит от переменной a
которая определяется вне ее области. Таким образом, если a изменен, результат функции impure
функции будет отличаться.
Чистая функция
let pure = (input) => {
let a = 1;
// Multiply with variable inside function scope
let output = input * a;
return output;
}
console.log(pure(2)) // Logs 2
Результат функции pure
не зависит от какой-либо переменной вне ее.