柯里化&compose函数

247 阅读2分钟

curring: 柯里化函数

  • 一种预先存储的思想,也是闭包的进阶运用,利用闭包的保存作用

例子1

const fn = (...params) => 
    (args) => params.concat(args).reduce((res, item) => res + item);
let res = fn(1, 2)(3);
console.log(res);// 6

例子2

// 跟据结果写curring函数
  const curring = () => {
    // EC回产生闭包
    let params = [];
    const add = (...arg) => {
      params = params.concat(arg);
      return add;
    }
    // 再把对象转为数字的时候,我们对params进行求和即可
    add[Symbol.toPrimitive] = () => params.reduce((res, item) => res + item);
    return add;
  }

  let add = curring();
  res = add(1)(2)(3);
  console.log(+res);//6 
  // =>把res(add函数)转换为数字经历: Symbol.toPrimitive -> valueOf -> toString..

  add = curring();
  res = add(1, 2, 3)(4);
  console.log(+res);// 10

  add = curring();
  res = add(1)(2)(3)(4)(5);
  console.log(+res);// 15
  // 新版的浏览器的console.log()不会转字符串了,需要用"+"去触发流程,老版本的不需要

例子3

/*
  在函数式编程中当有一个很重要的概念就是函数组合,实际上就是把处理数据的函数像管道一样连接起来
  然后让数据穿过管道最终的结果如下
  const add1 = x => x + 1;
  const mul3 = x => x * 3;
  const div2 = x => x / 2;
  div2(mul3(add1(add1(0))));// => 3

  这样的写法可读性太差了,我们可以构建一个compose函数,它接受任意多个函数作为参数
  (这些函数只接受一个参数),
  
  然后 compose 返回的也是一个函数,达到一下的效果
  const operate = compose(div2, mul3, add1, add1);
  operate(0) // 相当于div2(mul3(add1(add1(0))))
  operate(2) // 相当于div2(mul3(add1(add1(2))))
*/
const add1 = x => x + 1;
  const mul3 = x => x * 3;
  const div2 = x => x / 2;

  const compose = (...funcs) => {
    let len = funcs.length;
    // 判空的情况
    if(len === 0) {
      return x => x
    }
    if(len === 1) {
      return funcs[0];
    }
    return (x) => {
      // 第一个函数执行的初始实参 x = 0;
      // 从右向左迭代
      return funcs.reduceRight((x, fn) => {
        return fn(x);
      }, x)
    }
  }

  const operate = compose(div2, mul3, add1, add1);
  console.log(operate(0));// 3
  console.log(operate(2));// 6
  • redux源码方式实现上一例子
function compose(...funcs) {
    let len = funcs.length;
    if (len === 0) return x => x;
    if (len === 1) return funcs[0];
    //假设: funcs = [div2, mul3, add1]
    // 第一轮: a = div2 b= mul3 返回 (..args) => div2(mul3(...args)) @1
    // 第二轮: a = @1   b = add1 返回 x => @1(add1(x)) ==> operate
    // operate(0) ==> div2(mul3(add1(0)))
    return funcs.reduce((a, b) => {
      return (...args) => {
        return a(b(...args));
      }
    })
}