柯里化
柯里化
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返回结果