zl程序教程

您现在的位置是:首页 >  其它

当前栏目

柯里化

柯里化
2023-09-11 14:15:01 时间

本文整理自https://medium.com/@kj_huang/implementation-of-lodash-curry-function-8b1024d71e3b

https://www.jianshu.com/p/822c4bfeb8a9

const curry = fn => (...args) => fn.bind(null, ...args)

上面这种简写法第一次看不明白,改变一下,加一个括号即可:

const curry = fn => ((...args) => fn.bind(null, ...args))

再换成ES5的写法,更清晰:

var curry = function (fn) {
  return function () {
    var newFn,
    length = arguments.length;
    index = -1;

    while (++index < length) {
      newFn = fn.bind(null, arguments[index]);
    }
    
    return newFn;
  }
}

上面是一个 curry 函数,它返回“参数收集器”,该收集器只收集一次参数,并返回绑定的目标函数。

柯里化函数的目标:

1.在多个函数调用中逐步收集参数,不用在一个函数调用中一次收集。

2.当收集到足够的参数时,返回函数执行结果。

下面是两种实现:

实现一

function magician(targetfn) {
  var numOfArgs = targetfn.length;
  return function fn() {
    if (arguments.length < numOfArgs) {
      return fn.bind(null, ...arguments);
    } else {
      return targetfn.apply(null, arguments);
    }
  }
}

当参数收集齐时,通过闭包引用到原函数,apply调用返回结果

实现二

function magician (targetfn) {
  var numOfArgs = targetfn.length;
  if (arguments.length - 1 < numOfArgs) {
    return magician.bind(null, ...arguments);
  } else {
    return targetfn.apply(null, Array.prototype.slice.call(arguments, 1));
  }
}

原函数显式得定义为targetfn,以便收集齐参数后调用,当没有收集齐参数的时候,返回magician本身绑定之前的参数列表,参数列表里第一个参数一直是原函数,所以最后调用的时候要把第一个参数去掉

实现三

加入类似lodash的_.curry的占位符功能

function magician4 (targetfn, preset = []) {
  var numOfArgs = targetfn.length;

  if (preset.filter(arg => arg !== _).length === numOfArgs) {
    return targetfn.apply(null, preset);
  } else {
    return function (...added) {
      var newPreset = [...preset]
      var nextPos = 0;
      while(added.length > 0) {
        var a = added.shift();
        while (newPreset[nextPos] !== _ && nextPos < newPreset.length) {
          nextPos++
        }
        newPreset[nextPos] = a;
        nextPos++;
      }
      return magician3.call(null, targetfn, newPreset);
    }
  }
}

下面是其他写法:

const curry = (fn, ...args) => fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args);

收集参数,判断参数长度和fn期望参数长度是否一样或者大于,如果不是,就继续收集,直到收集齐了,就调用fn返回结果