如何捕获函数中所需的参数数(套用函数部分应用程序)

how capture the arguments number need in a function (currying function partial application)

本文关键字:函数部 应用程序 数数 参数 函数 何捕获      更新时间:2023-09-26

我正在研究循环函数和部分应用程序,我正在尝试改进schonfinkelize函数:

        function schonfinkelize(fn){
            var 
                slice = Array.prototype.slice,
                stored_args = slice.call(arguments, 1);
            return function(){
                var 
                    new_args = slice.call(arguments),
                    args = stored_args.concat(new_args);
                return fn.apply(null, args);
            }
        }

这个函数允许传递作为参数,函数作为参数传递的函数的一部分参数(部分应用程序),所以第一次返回一个函数,然后当你再次触发函数的结果。

function add(x, y, z){
    return x + y + z;
}
var val = schonfinkelize(add, 1, 2);
console.log( val(3) ) // console output--> 6

我想在schonfinkelize内部检查函数"add"所需的参数数量(但它应该与每个函数一起工作),所以我可以选择何时返回另一个函数或直接返回函数"add"的结果。

因为如果我这样使用schonfinkelize

var val2 = schonfinkelize(add, 1, 2, 3);
console.log( val2 )    // --> function
console.log( val2() )  // --> 6

我必须两次触发函数,而不是想避免这种行为,如果参数足够,直接定义值


一个可能的解决方案如下:

        function schonfinkelize(fn){
            var 
                slice = Array.prototype.slice,
                stored_args = slice.call(arguments, 1);

                //* I have added this ********
                if(fn.apply(null, stored_args))
                    return fn.apply(null, stored_args);
                //****************************
            return function(){
                var 
                    new_args = slice.call(arguments),
                    args = stored_args.concat(new_args);
                return fn.apply(null, args);
            }
        }

可能是因为它立即返回fn的结果。apply(null, stored_args)返回的东西不是"null"或"NaN",但我认为不是真正的性能,然后我想工作与参数

只要您要求为传递的函数定义的参数反映最终要接收的参数的实际数量,您就可以使用函数的.length属性将传递的参数与预期的参数进行比较。

function schonfinkelize(fn) {
    if (fn.length === arguments.length - 1)
        return fn.apply(this, [].slice.call(arguments, 1));
    var 
        slice = Array.prototype.slice,
        stored_args = slice.call(arguments, 1);
    return function(){
        var 
            new_args = slice.call(arguments),
            args = stored_args.concat(new_args);
        return fn.apply(null, args);
    }
}

边注…如果您将fn缓存到一个新变量中,并使用this值覆盖第一个参数,则可以避免.slice(),然后使用.call.apply()

    if (fn.length === arguments.length - 1) {
        var func = fn;
        arguments[0] = this;
        return func.call.apply(func, arguments);
    }

严格模式浏览器中,您甚至可以避免使用make the new variable,因为参数不再映射到arguments中的更改。但这在不支持严格模式的浏览器中不起作用

我不认为有一个正确的方法来确定任意函数的参数数量。如果有必要,我更喜欢将len存储在函数中,并检查它是否被定义,如果是,如果fn.len == stored_args.length则返回函数,仅返回值。

function schonfinkelize(fn){
  var 
    slice = Array.prototype.slice,
    stored_args = slice.call(arguments, 1);
  if (fn.len != undefined && fn.len == stored_args.length) {
    var val = fn.apply(null, stored_args);
    return function () {
      return val;
    };
  }
  return function () {
    var 
      new_args = slice.call(arguments),
      args = stored_args.concat(new_args);
    return fn.apply(null, args);
  };
}
var f = function (a, b, c) {
  return a + b + c;
};
f.len = 3;
var g = schonfinkelize(f, 1, 2);
alert(g); // function () { var new_args = slice.call(arguments), args = stored_args.concat(new_args); return fn.apply(null, args); };
alert(g(3)); // 6
var g = schonfinkelize(f, 1, 2, 3);
alert(g); // function () { return val; };
alert(g()); // 6

我还想提出一个个人的代码演变,但我不得不说感谢斜眼已经解决了这个问题,只是建议我使用属性.length。在我看来,下一个层次是允许创建一个局部函数,每次都可以调用它,直到完成填充所有参数,我也简化了代码:

        function schonfinkelize(fn, stored_args){
            if(fn.length == stored_args.length)
                return fn.apply(null, stored_args);
            return function(){
                var 
                    new_args = arguments[0],
                    args = stored_args.concat(new_args);
                if(fn.length == args.length)
                    return fn.apply(null, args);
                return schonfinkelize(fn, args);
            }   
        }

        function add(x, y, w, z){
            return x + y + w + z;
        }

        var 
            val  = schonfinkelize(add, [1, 2, 3, 4]),
            val2 = schonfinkelize(add, [1, 2]),
            val3 = schonfinkelize(add, [1]);

        // checking
        console.log(val);           // output --> 10 // called only 1 time
        console.log(val2([3, 4]));  // output --> 10 // called in 2 times
        val3 = val3([2]);
        val3 = val3([3]);
        console.log(val3([4]));     // output --> 10 // called 4 times!
相关文章: