Master Functional Programming in JavaScript: Currying, Pipe, Compose
This article introduces functional programming fundamentals, showcases common JavaScript scenarios like map/filter/reduce, explains key concepts such as first‑class functions, laziness, pure functions, currying, pipe, and compose, and demonstrates their practical application in a real‑world AgileBI report‑cell configuration system.
Function Programming Overview
Functional programming is a paradigm that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. In JavaScript it enables higher‑order functions, currying, composition, and lazy evaluation to write more reusable and declarative code.
Common Application Scenarios
ES6 array methods such as map, filter, reduce React class components transformed to functional components with hooks; Vue 3 composition API
Libraries like RxJS, Lodash, Ramda
Middleware/plug‑ins, e.g., Redux
applyMiddleware [1,2,3,4,5].map(x => x * 2).filter(x => x > 5).reduce((p,n) => p + n); const store = applyMiddleware(...middlewares)(createStore)(reducer, initialState);What Is Functional Programming?
It abstracts programs into pure functions and immutable data structures, allowing functions to be passed as arguments and returned as results. In JavaScript it can emulate object‑oriented features such as abstraction, encapsulation, inheritance, and polymorphism while supporting higher‑order functions, currying, composition, and lazy evaluation.
Key Characteristics
First‑Class Functions
Functions can be passed to other functions and returned as values, enabling higher‑order functions.
Lazy Execution
Computations are deferred until their results are needed, improving performance by avoiding unnecessary work.
No Side Effects (Pure Functions)
Pure functions do not modify external state; they return the same output for the same input without causing side effects.
Common Functional Concepts
Currying
Transforms a function with multiple arguments into a sequence of functions each taking a single argument.
// Currying example
function curry(fn, args) {
args = args || [];
return function(...params) {
const _args = [...args, ...params];
if (_args.length < fn.length) {
return curry(fn, _args);
}
return fn.apply(this, _args);
};
}
function sum(a, b, c) { return a + b + c; }
const currySum = curry(sum);
console.log(currySum(1)(2)(3)); // 6
console.log(currySum(1)(2, 3)); // 6
console.log(currySum(1, 2)(3)); // 6Pipe
The pipe function composes functions left‑to‑right, passing each result to the next.
export const pipe = (...fns) => input =>
fns.reduce((chain, fn) => chain.then(fn), Promise.resolve(input));Compose
The compose function composes functions right‑to‑left.
export const compose = (...fns) => input =>
fns.reduceRight((chain, fn) => chain.then(fn), Promise.resolve(input));Practical Case: AgileBI Cell Configuration
AgileBI is an online reporting tool that allows drag‑and‑drop creation of complex reports. A new requirement adds batch configuration for cells, supporting expansion direction, parent cell linking, and full configuration for text, field, and formula cells.
The implementation uses higher‑order handlers for each configuration aspect and a custom pipe to apply them sequentially.
private pipe = (...args) => {
return (result, config) => {
return args.reduce((acc, fn) => fn(acc, config), result);
};
};
// Example handlers
private handleExpand(expandConf) {
return conf => {
if (expandConf) conf.expandDirection = expandConf;
return conf;
};
}
private handleParentCell(columnParentCell, rowParentCell) {
return conf => {
if (columnParentCell?.parentSelectType) conf.columnParentCell = columnParentCell;
if (rowParentCell?.parentSelectType) conf.rowParentCell = rowParentCell;
return conf;
};
}
// ... other handlers (format, filter, condition)
let handles = [];
if (cell?.dataConf?.cellType === "文本") {
handles = [this.handleExpand(conf.expandDirection), this.handleParentCell(conf.columnParentCell, conf.rowParentCell)];
} else if (cell?.dataConf?.cellType === "字段" || cell?.dataConf?.cellType === "公式") {
handles = [
this.handleExpand(conf.expandDirection),
this.handleParentCell(conf.columnParentCell, conf.rowParentCell),
this.handleFormat(conf.dataFormatConf),
this.handleFilter(conf.cellFilterConf),
this.handleCondition(conf.conditionConf)
];
}
if (handles.length > 0) {
const mergeConf = this.pipe(...handles)(JSON.parse(JSON.stringify(cell.dataConf)));
// apply mergeConf …
}Conclusion
Functional programming improves code reusability and reduces duplicate development effort.
It enhances readability, making code easier to understand and debug.
Function composition simplifies maintenance and promotes modular design.
Composition is often preferable to inheritance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JD Cloud Developers
JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
