详解JS中的compose函数和pipe函数用法

作者:闭包旅人时间:2026-10-24 09:57:58浏览:420

本文深入解析JavaScript中compose与pipe函数的实现原理。通过结合Array.prototype.reduce和reduceRight方法,详细演示如何将嵌套函数调用平铺为线性执行链。文章涵盖ES5与ES6两种写法,并对比了从右向左与从左向右的执行顺序差异,适用于Redux中间件及Webpack Loader等场景。

compose函数

compose函数的核心作用是将需要嵌套执行的多个函数进行平铺处理。所谓嵌套执行,是指前一个函数的返回值直接作为下一个函数的输入参数。以一个简单的计算需求为例,我们可以直接编写一个计算函数来完成:


const calculate = x => (x + 10) * 10;
let res = calculate(10);
console.log(res);    // 200

然而,遵循函数式编程的思想,我们可以将复杂的计算逻辑拆解为多个简单且可复用的步骤。例如,我们将上述逻辑拆分为一个加法函数和一个乘法函数:


const add = x => x + 10;
const multiply = x => x * 10;

// 我们的计算改为两个函数的嵌套计算,add函数的返回值作为multiply函数的参数
let res = multiply(add(10));
console.log(res);    // 结果还是200

上述计算方式属于函数的嵌套执行。而compose函数的作用,正是将这些嵌套执行的函数作为参数进行平铺。在嵌套执行过程中,位于右侧(内部)的函数最先执行,结果向左传递;同理,compose函数也是从参数列表的最右侧开始执行。因此,我们的目标是实现一个具备此类特性的compose方法:


// 参数从右往左执行,所以multiply在前,add在后
let res = compose(multiply, add)(10);

在实现compose之前,我们需要先了解一个基础数组方法:Array.prototype.reduce。

Array.prototype.reduce

数组的reduce方法主要用于实现累加效果。它接收两个参数:第一个是累加器函数,第二个是初始值。累加器函数接收四个参数,其中前两个最为常用:第一个参数代表上一次迭代返回的值(累加器),第二个参数代表数组当前的元素。后两个参数分别为当前元素的索引和数组本身,通常在基础累加中较少使用:


const arr = [[1, 2], [3, 4], [5, 6]];
// prevRes的初始值是传入的[],以后会是每次迭代计算后的值
const flatArr = arr.reduce((prevRes, item) => prevRes.concat(item), []);

console.log(flatArr); // [1, 2, 3, 4, 5, 6]

Array.prototype.reduceRight

Array.prototype.reduce默认从左向右进行迭代。若需要实现从右向左的迭代逻辑,则应使用Array.prototype.reduceRight方法。


const arr = [[1, 2], [3, 4], [5, 6]];
// prevRes的初始值是传入的[],以后会是每次迭代计算后的值
const flatArr = arr.reduceRight((prevRes, item) => prevRes.concat(item), []);

console.log(flatArr); // [5, 6, 3, 4, 1, 2]

基于reduceRight方法,我们可以实现compose函数。具体实现如下:


const compose = function(){
  // 将接收的参数存到一个数组, args == [multiply, add]
  const args = [].slice.apply(arguments);
  return function(x) {
    return args.reduceRight((res, cb) => cb(res), x);
  }
}

// 我们来验证下这个方法
let calculate = compose(multiply, add);
let res = calculate(10);
console.log(res);    // 结果还是200

若使用ES6语法,上述compose函数的写法可以更加简洁:


const compose = (...args) => x => args.reduceRight((res, cb) => cb(res), x);

Redux框架中的中间件机制正是基于compose函数实现的。此外,Webpack中Loader的加载顺序也是从右向左执行,这同样得益于compose函数的实现逻辑。

pipe函数

pipe函数与compose函数的执行方向相反,同样是将参数进行平铺,但其执行顺序是从左向右。实现方式仅需将reduceRight替换为reduce即可:


const pipe = function(){
  const args = [].slice.apply(arguments);
  return function(x) {
    return args.reduce((res, cb) => cb(res), x);
  }
}

// 参数顺序改为从左往右
let calculate = pipe(add, multiply);
let res = calculate(10);
console.log(res);    // 结果还是200

使用ES6语法的pipe函数写法如下:


const pipe = (...args) => x => args.reduce((res, cb) => cb(res), x)

以上就是对JavaScript中compose函数和pipe函数用法的详细解析,更多JavaScript相关技术文章请持续关注本站。

作者最新文章