1

我正在研究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);
            }
        }

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

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”,但我认为它的性能并不高,然后我想使用这些参数,它会立即返回结果。

4

3 回答 3

1

我认为没有正确的方法来确定任意函数的参数数量。如果有必要,我更喜欢存储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
于 2013-05-10T11:58:43.360 回答
1

只要您要求为传递的函数定义的参数反映最终要接收的参数的实际数量,您就可以使用.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);
    }
}

旁注......你可以避免.slice()如果你缓存fn在一个新变量中,并用该值覆盖第一个参数this,然后使用.call.apply()......

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

严格模式浏览器中,您甚至可以避免使用新变量,因为参数不再映射到arguments. 但这在不支持严格模式的浏览器中不起作用。

于 2013-05-10T16:42:10.840 回答
0

我还想提出代码的个人演变,但我不得不说感谢 squint 解决了这个问题,只是建议我使用属性.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!
于 2013-05-10T17:04:14.057 回答