function curry(fn, args, holes) {
let length = fn.length;//fn的形参的长度
args = args || [];//fn的实参
holes = holes || [];//占位符数组
return function (...args2) {
let _args = args.slice(0),//存放组合后的参数
argsLen = args.length,//fn的实参的长度
for (let i = 0; i < args2.length; i++) {
// 处理类似 fn(1, _, _, 4)(_, 3) 这种情况,index 需要指向 holes 正确的下标
if (arg === _ && holesLen) {
_holes.push(argsLen - 1 + index - holesLen);
_holes.push(argsLen + i);
// fn(_, 2)(1) 用参数 1 替换占位符
_args.splice(_holes[index], 1, arg);
if (_holes.length || _args.length < length) {
return curry.call(this, fn, _args, _holes);
return fn.apply(this, _args);
///////////////////////开始测试/////////////////////////
let _ = { '@@functional/placeholder':true};//定义一个占位符,这里参考Ramda的定义
let fn = curry(function (a, b, c, d, e) {
console.log([a, b, c, d, e]);
// 验证 输出全部都是 [1, 2, 3, 4, 5]
fn(1, _, _, 4)(_, 3)(2)(5);
fn(_, 2)(_, _, 4)(1)(3)(5);