Function composition in JavaScript is process of combining several function calls into one function.
Ways in which function composition can be done
- Creating a high-order function and pass the necessary functions as parameters in this method.
- Using
reduce()
orreduceright()
function and pass all the independent functions that needs to be combined.
Let's see how can this be done
Approach 1 : Using higher order functions
UseCase: If we have a scenario where we need to print details of employee on some kind of employee card for each employee and we have three independent functions.
Code for the example is written below
// 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
the print(funcA, funcB)
function takes a bigger form .i.e. more lines of code when we need to add more functions to the composition.
Approach 2: Using reduce() or reduceRight() functions for function composition
For same use case as above , second way of doing function composition in JavaScript is by using reduce()
or reduceRight()
functions.
JavaScript reduceRight()
function runs a function on each element of the array to reduce it into a single value. Also , reduceRight()
function executes elements from the right, whereas reduce() method executes elements from left.
It is noteworthy that functions objects being passed to the
reduce()
orreduceRight()
function should have same number of arguments in each of them, and it should also return one value
So, any function can be made composable by converting that function into a curry function
Currying is the technique in functional way of programming of transforming a function taking multiple input arguments (two, three or more- polyadic) into set of internally related functions by using closures, where each function is single input, single output function, and final output returned from the outermost function.
Simply written, currying is the way of reshaping the function type
f(a, b, c)
tof(a)(b)(c)
.
e.g.
//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');
So, functions in this case
// 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
The benefit of this approach for function composition is visually seen as our code base increases.
References
Top comments (0)