js - 理解函数组合

651 阅读2分钟

怎么理解函数组合

compose(f, g, t) => x => f(g(t(x))

函数组合,字面意思将多个函数有序组合起来。有序组合的原因是不同的顺序返回的函数是不同函数。

var { compose } = require('ramda')

const f = x => x + 1;

const g = x => x * 2;

const fg1 = compose(f, g);

const fg2 = compose(g, f);

console.log(fg1(4)) // 9
console.log(fg2(4)) // 10


解释一下,函数组合执行的顺序是从右向左

fg1:(4 * 2) + 1 = 9
fg2:(4 + 1) * 2 = 10


上面的ES5代码执行

var compose = function(f,g) {
  return function(x) {
    return f(g(x));
  };
};


当然这种写法不完善,因为只支持两个函数的输入。

手写函数组合

分解

  1. 返回高捷函数
  2. 高阶函数可以从右往左依次执行方法,并且将上一个方法的返回值传入到下一个方法中。


这个依次执行的方式可以想到的reduce和reduceRight方法,reduce方法就是将前一次循环得到的结果当成下次循环执行的参数。

手写版本

var compose = function() {
	const funcArray = [...arguments];
  
  return function () {
  	return funcArray.reduceRight(
      (arg, fn) => {
        return fn.apply(null, [].concat(arg)) // 这里使用这个是因为第一个执行的函数可能存在两个参数(最右边的函数)
      }, 
      [...arguments]
    )
  }
}


高颜值版本

var compose = (...fns) => (...args) => fns.reduceRight((arg, fn) => fn.apply(null, [].concat(arg)), args)


underscore 的 compose 函数

function compose() {
    var args = arguments;
    var start = args.length - 1;
    return function() {
        var i = start;
        var result = args[start].apply(this, arguments);
        while (i--) result = args[i].call(this, result);
        return result;
    };
};


redux 中 compose

function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

理解一下:

function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => {
    return (...args) => {
        return a(b(...args))
        }
    })
}


const f = x => x + 1;

const g = x => x * 2;

const h = x => x + 3;

let fg1 = compose(f, g, h);
let g2 = compose(h, g, f);

console.log(fg1(4)) 
console.log(fg2(4))

函数组合执行是从右向左的,reduce则是从左向右形成高阶函数。

let fg1 = compose(f, g, h);

return function(arg) {
	return f(g(h(arg)))
}


Ramda中的pipe【从左到右的组合】

var { compose, pipe } = require('ramda')

const f = x => x + 1;

const g = x => x * 2;

const fg1 = compose(f, g);

const fg2 = pipe(g, f);

console.log(fg1(4)) // 9
console.log(fg2(4)) // 9


应用

react高阶函数使用

withRoute(observer(inject('Store')(Index)))

const enhance = compose(withRoute, observer, inject('Store'));

enhance(Index);

参照