Композиция функций в JavaScript — это процесс объединения нескольких вызовов функций в одну функцию.
Способы, с помощью которых может быть выполнена композиция функций
- Создание функции высокого порядка и передача необходимых функций в качестве параметров в этот метод.
- Использование функции
reduce()
илиreduceright()
и передача всех независимых функций, которые необходимо объединить.
Давайте посмотрим, как это можно сделать
Подход 1: Использование функций более высокого порядка
UseCase: Если у нас есть сценарий, в котором нам нужно распечатать данные о сотруднике на некоторой карточке сотрудника для каждого сотрудника, и у нас есть три независимые функции.
Код для примера приведен ниже
// function1 to print employee id
const printId = (employeeId) =>{
console.log("Printing| EmployeeId:", employeeId);
}
//function2 to print employee name
function printname(name) {
console.log("Printing| Name:", name);
}
//function3 to print email and designation among other info.
const printOther = (email, designation) =>{
console.log(`Printing| Email: ${email} ,Designation: ${designation}`);
}
//function 4 is an higher order function that runs the functions being passed into it
const print = (funcA, funcB) => (param_ToFunctionB) =>
funcA(funcB(param_ToFunctionB));
//printing the combination of above js functions
print(
printId(1234),
print(
printname("Rahul"),
printOther("rahul@web.com", "software engineer")
)
);
//output
Printing| EmployeeId: 1234
Printing| Name: Rahul
Printing| Email: rahul@web.com ,Designation: software engineer
функция print(funcA, funcB)
принимает более объемную форму .т.е. больше строк кода, когда нам нужно добавить больше функций в композицию.
Подход 2: Использование функций reduce() или reduceRight() для композиции функций
Для того же случая использования, что и выше, второй способ выполнения композиции функций в JavaScript — использование функций reduce()
или reduceRight()
.
Функция JavaScript reduceRight()
выполняет функцию на каждом элементе массива, чтобы уменьшить его до одного значения. Кроме того, функция reduceRight()
выполняет элементы справа, в то время как метод reduce() выполняет элементы слева.
Примечательно, что объекты функций, передаваемые функции
reduce()
илиreduceRight()
, должны иметь одинаковое количество аргументов в каждом из них, а также возвращать одно значение.
Таким образом, любую функцию можно сделать композиционной, преобразовав ее в функцию карри.
Карри — это техника в функциональном программировании, позволяющая преобразовать функцию, принимающую множество входных аргументов (два, три или более — полиадические), в набор внутренне связанных функций с помощью замыканий, где каждая функция является единственной входной, единственной выходной функцией, а конечный выход возвращается из самой внешней функции.
Проще говоря, замыкание — это способ преобразования типа функции
f(a, b, c)
вf(a)(b)(c)
.
например.
//normal function call
const departmentEmployees=(departmentName,empId,empName)=>{
console.log(`${departmentName} Info| ${empId} :: ${empName}`);
return true;
}
//transformed carried function
const departmentCarryTransformed = (departmentName)=>(empId)=>(empName)=>{
console.log(`${departmentName} Info | ${empId} :: ${empName}`);
return true;
}
//carry function benefit
//we can create single global variable for a department and use it elsewhere across the file or the page
let accountsDepartment= departmentCarryTransformed("Accounts");
accountsDepartment(123)('bob');
accountsDepartment(2)('tom');
Таким образом, функции в данном случае
// function1 to print employee id
const printId = (attributes) => {
console.log("Printing| EmployeeId:", attributes.employeeId);
return attributes;
};
//function2 to print employee name
function printname(obj) {
console.log("Printing| Name:", obj?.name);
return obj;
}
//function3 to print email and designation among other info.
const printOther = (attributes) => {
console.log(
`Printing| Email: ${attributes?.email} ,Designation: ${attributes?.designation}`
);
};
// TO make the function composition easier, we can use rest parameters to pass indefinite number of arguments to the function
const smarterPrint =
(...functions) =>
(params) => functions.reduceRight((p, fn) => fn(p),params);
// parameters that we need to pass to different functions to print specific info
const fn_params = {
employeeId: 1234,
name: "rahul ranjan",
email: "rahul@web.com",
designation: "software engineer",
};
// this function composition way takes lesser code of lines.
smarterPrint(printOther, printname, printId)(fn_params);
// second way
const smarterPrintOtherWay = (paramsObj) => printOther(printname(printId(paramsObj)));
smarterPrintOtherWay(fn_params);
//output is same
Printing| EmployeeId: 1234
Printing| Name: Rahul
Printing| Email: rahul@web.com ,Designation: software engineer
Преимущество такого подхода к композиции функций наглядно видно по мере увеличения нашей кодовой базы.
Ссылки
- https://javascript.info/currying-partials
- https://jrsinclair.com/articles/2022/javascript-function-composition-whats-the-big-deal/
- https://medium.com/hackernoon/javascript-functional-composition-for-every-day-use-22421ef65a10