简体   繁体   English

如何捕获函数中需要的参数数量(循环函数部分应用程序)

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

I am working on the curring function and partial application, I am trying to improve the function schonfinkelize: 我正在研究curring函数和部分应用程序,我正在尝试改进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);
            }
        }

This function permit to pass as argument a function and a part of the argument of the function passed as argument (partial application) so the first time you return a function and then when you fire the function again the result. 此函数允许将一个函数作为参数传递,并将函数 的一部分参数作为参数传递(部分应用程序),因此,第一次返回函数,然后再次触发该函数时,将返回结果。

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

var val = schonfinkelize(add, 1, 2);

console.log( val(3) ) // console output--> 6

I want check inside schonfinkelize the number of arguments need to the function "add" (but it should work with every function) so I can choose when return another function or directly the result of the function "add". 我想在schonfinkelize内部检查功能“ add”所需的参数数量(但它应与每个功能一起使用),以便我可以选择何时返回另一个功能或直接选择“ add”功能的结果。

bacause if I use schonfinkelize in this way: 因为如果我以这种方式使用schonfinkelize:

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

I have to fire the function two time, instead a want avoid this behavior and define directly the value if the arguments are sufficient . 我必须两次触发该函数,而要避免这种行为,如果参数足够,则直接定义该值


A possible solution could be the following: 可能的解决方案如下:

        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);
            }
        }

Could be because it returns immediately the result if the fn.apply(null, stored_args) return something that is not "null" or "NaN" but I think is not really performant and then I want work with the arguments. 可能是因为,如果fn.apply(null,stored_args)返回的结果不是“ null”或“ NaN”,但我认为它并不是真正的高性能,那么它会立即返回结果,然后我想使用这些参数。

I don't think there is a correct way to determine number of arguments for arbitrary function. 我认为没有正确的方法来确定任意函数的参数数量。 I prefer to store len in function if it is necessary, and check if it is defined, and if it is and if fn.len == stored_args.length then return function that just returns value. 我宁愿在必要时将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

As long as you put in place a requirement that the parameters defined for the function passed reflect the actually number of arguments that are to be ultimately received, you can use the .length property of the function to do the comparison of passed arguments to anticipated arguments. 只要您对传递的函数定义的参数提出要求,以反映最终要接收的实际参数个数,就可以使用函数的.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);
    }
}

Side note... you can avoid the .slice() if you cache the fn in a new variable, and overwrite the first argument with the this value, then use .call.apply() ... 侧面说明...你可以避开.slice()如果缓存fn在一个新的变量,并与覆盖的第一个参数this值,然后使用.call.apply() ...

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

In strict mode browsers you could even avoid having the make the new variable since the parameters are no longer mapped to changes in the arguments . 严格模式的浏览器中,您甚至可以避免使用make new变量,因为参数不再映射为arguments更改。 But this doesn't work in browsers that don't support strict mode . 但这在不支持严格模式的浏览器中不起作用。

I want propose also a personal evolution of the code but I have to said thanks to squint to has resolved the problem, simply suggest me to use the property .length . 我也想提出代码的个人发展,但是我不得不感谢斜视解决了这个问题,只是建议我使用.length属性。 The next level it is in my opinion permit to create a partial function able to be called every time you want until you finish to fill all the arguments, I have also simplified the code: 我认为允许创建下一个函数,可以每次调用它的下一个层次,直到完成所有参数的填充为止,我还简化了代码:

        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!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM