一、compose 的实现:
compose 函数实现详解(函数式编程核心工具)
compose 是函数式编程的核心工具,用于将多个函数组合成从右向左执行的管道。
1. 基础实现(ES5)
function compose(...fns) {
return function (initialValue) {
return fns.reduceRight((acc, fn) => fn(acc), initialValue);
};
}
原理:
reduceRight 从右向左遍历函数数组;
每个函数的输出作为下一个函数的输入;
初始值:initialValue;
2. ES6 箭头函数精简版
const compose = (...fns) =>
(x) => fns.reduceRight((acc, fn) => fn(acc), x);
3. 支持异步函数(Promise)
const asyncCompose = (...fns) =>
(x) => fns.reduceRight(
(acc, fn) => acc.then(fn),
Promise.resolve(x)
);
使用示例
// 功能函数
const toUpperCase = str => str.toUpperCase();
const exclaim = str => str + '!';
const reverse = str => str.split('').reverse().join('');
// 组合函数
const loudReverse = compose(exclaim, toUpperCase, reverse);
console.log(loudReverse('hello')); // "OLLEH!"
执行流程:
原始值: 'hello'
1. reverse('hello') → 'olleh'
2. toUpperCase('olleh') → 'OLLEH'
3. exclaim('OLLEH') → 'OLLEH!'
高级实现(支持多参数初始函数)
function compose(...fns) {
return fns.reduce((f, g) =>
(...args) => f(g(...args))
);
}
// 使用
const calculate = compose(
x => x * 2, // 第三步:乘2
(x, y) => x + y, // 第二步:加法
(x, y) => x * y // 第一步:乘法
);
console.log(calculate(3, 4)); // (3*4)=12 → (12+4)=16 → (16*2)=32
性能优化版(避免嵌套调用栈)
function compose(...fns) {
const length = fns.length;
return function(...args) {
let index = length - 1;
let result = fns[index].apply(this, args);
while (index--) {
result = fns[index].call(this, result);
}
return result;
};
}
优势:
避免递归调用栈溢出
适合组合大量函数 (>1000)
实际应用场景
React 高阶组件
const enhance = compose(
withRouter,
connect(state => ({ user: state.user })),
withStyles(styles)
);
export default enhance(Component);
数据处理管道
const cleanData = compose(
removeDuplicates,
filterInvalidRecords,
normalizeDates
);
const report = cleanData(rawDataset);
中间件链(Redux/Koa)
// Koa-style middleware
const app = compose(
middleware1,
middleware2,
controller
);
Lodash 对应实现:_.flowRight
Ramda 对应实现:R.compose
设计要点
函数顺序:从右向左执行(数学函数组合标准)
数据流向:前一函数的输出 = 后一函数的输入
纯函数要求:所有组成函数应为纯函数
参数要求:除最右函数外,其它函数应接收单参数
二、pipe 函数
pipe 用于将多个函数组合成从左向右执行的管道。
实现方式:从左向右的 pipe(与 compose 方向相反)
// compose(f, g, h)(x) = f(g(h(x)))
// pipe(h, g, f)(x) = f(g(h(x)))
const pipe = (...fns) =>
(x) => fns.reduce((acc, fn) => fn(acc), x);