В этом примере нет реальной разницы в выводе.Однако давайте сделаем это еще проще:
function add(a) {
return function(b) {
return a+b;
}
}
console.log(add(1)(2));
function add(a, b) {
return a+b;
}
console.log(add(1, 2));
Для простоты функция принимает два параметра.Один раз вы должны передать их обоих при вызове, другой вы должны передать их один за другим.Давайте посмотрим, как это может быть полезно:
function add(a) {
return function(b) {
return a+b;
}
}
let numbers = [1, 2, 3, 4, 5, 6];
//lets add the same number to all members of the array:
const numberToAdd = 5;
//traditionally
const newArray = []; //make a new array
for (let num of numbers) { //define a loop
newArray.push(num + numberToAdd); //populate the array
}
console.log(newArray);
//functional
const mappedArray = numbers.map(num => num + numberToAdd); //using .map to handle everything
console.log(mappedArray);
//using the function we have
const betterMappedArray = numbers.map(add(numberToAdd));
console.log(betterMappedArray);
Таким образом, функциональный подход с помощью .map
короче и проще, но может быть еще более улучшен путем передачи функции.Без функции add
вы по-прежнему передаете функцию, вы определяете новую функцию сложения каждый раз, когда вы хотите просто добавить что-либо в массив.Если вы хотите добавить переменные суммы, то без add
вам нужно создать две новые функции, которые в основном все делают одно и то же
function add(a) {
return function(b) {
return a+b;
}
}
let numbers = [1, 2, 3, 4, 5, 6];
console.log("using .map() with new functions");
console.log(
numbers
.map(num => num + 5)
.map(num => num + 10)
);
console.log("using .map() with add()");
console.log(
numbers
.map(add(5))
.map(add(10))
);
Как видите, поставить бок о бок кажется довольно расточительным, чтобы каждый раз создавать новые функции.Даже при наличии подписи add(a, b)
, то есть двух аргументов, вам придется вызывать numbers.map(num => add(num, 5))
, что ничего не улучшит.
Имейте в виду, что add
действительно просто - у вас может быть функцияэто сложнее.Тем не менее, перейдя к простому примеру, давайте перепишем пример, чтобы показать, как он может быть полезен:
function add(a) {
return function(b) {
return a+b;
}
}
const shoppingCart = [
{name: "item1", price: 1},
{name: "item2", price: 2},
{name: "item3", price: 3},
{name: "item4", price: 4},
{name: "item5", price: 5},
{name: "item6", price: 6},
];
const applyHandlingTax = add(5);
const applyShippingTax = add(10);
const numbers = shoppingCart.map(item => item.price); //extract prices from the shopping cart
const finalPrices = numbers
.map(applyHandlingTax)
.map(applyShippingTax);
console.log(finalPrices);
Это наивный пример с преувеличенными числами, но он просто показывает, что мы можем сделать здесь.Функционально он такой же, как и в предыдущем фрагменте, но, как вы можете видеть, теперь у нас есть бизнес-логика практически без изменений.
- Мы определили
applyHandlingTax
как добавление 5
.Мы также определили applyShippingTax
для добавления 10
. - Обе эти функции являются функциями, поэтому мы можем применить их через
.map
непосредственно к набору результатов, который у нас есть, уменьшая объем кода, который мыдолжен написать. - Бизнес-правило легко понять, поскольку вы пишете довольно читабельный для человека код - вам нужно совсем немного знаний о программировании, чтобы понять,
numbers.map(applyHandlingTax).map(applyShippingTax)
применяет налог на доставку и обработку к каждому из чисел.И как разработчик ясно, что вы добавляете налог на доставку и обработку. - Если мы уверены, что
add
работает правильно, то по определению все, что происходит из этого, также будет работать - нет необходимости проверять applyShippingTax
.Фактически, нечего проверять - нет тела функции, мы не написали для него никакой логики, мы используем только результат функции для него. - единственный значимый код, который мы написали, предназначен для определения
add
и извлечения цен из предметов.Даже в этом случае последний может быть легко абстрагирован так же, как мы сделали с add
, поэтому мы можем применить его к любому какому-либо набору результатов
function extract(name) {
return function(item) {
return item[name];
}
}
const shoppingCart = [
{name: "item1", price: 1},
{name: "item2", price: 2},
{name: "item3", price: 3},
{name: "item4", price: 4},
{name: "item5", price: 5},
{name: "item6", price: 6},
];
const people = [
{name: "Alice", drives: "Audi"},
{name: "Bob", drives: "BMW"},
{name: "Carol", drives: "Citroen"},
{name: "David", drives: "Dodge"},
{name: "Esther", drives: "EDAG"},
{name: "Fred", drives: "Ford"},
];
const prices = shoppingCart.map(extract('price'));
console.log(prices);
const names = people.map(extract('name'));
const cars = people.map(extract('drives'));
console.log(names);
console.log(cars);
Даже с довольно тривиальным примером add
мы можем продвинуться довольно далеко.Особый стиль написания add
известен как curry - вместо одновременного принятия X количества параметров, функция возвращает другую функцию, которая принимает X - 1 , пока не будет удовлетворено.
Функции, которые работают с другими функциями - либо производящие их (как add
делает), потребляющие их, либо обе они называются функциями высшего порядка .Если мы будем использовать их и последовательно каррировать, мы попадем на территорию функционального программирования .Написание полностью функционального стиля не является обязательным условием, чтобы извлечь из этого пользу - как мы видели в add
, вы можете написать простое приложение, не используя много кода, даже если мы применяем бизнес-правила.