如何传递带参数的函数引用?

95

可能是重复问题:
如何在JavaScript函数调用中预设参数?(部分函数应用)

我需要能够传递一个带有一组给定参数的函数引用

以下是传递没有参数的引用的示例:

var f = function () {
    //Some logic here...
};

var fr = f; //Here I am passing a reference to function 'f', without parameters
fr(); //the 'f' function is invoked, without parameters

现在我需要做的是传递相同的f函数,但这次我需要向引用传递参数。现在,我可以使用匿名函数并在新创建的函数内部使用参数调用f函数,像这样:

var f = function () {
        //Some logic here...
    };

var fr = function (pars) {
    f(pars);
}; //Here I am creating an anonymous function, and invoking f inside it

fr({p : 'a parameter'}); //Invoking the fr function, that will later invoke the f function with parameters

但我的问题是,有没有一种方法可以直接将带有参数的f函数的引用传递给fr,而不需要将其封装在匿名函数中?

我需要为fr分配什么内容,以便在调用fr时无需参数(fr()),执行f(1,2,3)?

[更新] 我遵循Jason Bunting这里关于部分函数的答案,并且他在那里发布的JavaScript函数正是我正在寻找的。以下是解决方案:

function partial(func /*, 0..n args */) {
  var args = Array.prototype.slice.call(arguments).splice(1);
  return function() {
    var allArguments = args.concat(Array.prototype.slice.call(arguments));
    return func.apply(this, allArguments);
  };
}

由于某些原因,我在第一条语句(var args = Array.prototype.slice.call(arguments).splice(1);)遇到了问题,不得不使用以下代码:var args = new Array(); for (var i = 1; i < arguments.length; i++) { args.push(arguments[i]); } - Rich Reuter
如果有人需要,可以使用以下代码:Function.prototype.pass = function(){ var args=arguments, func = this; return function(){ func.apply(this,args);} }; - Muhammad Umer
3个回答

81
你需要的是部分函数应用。不要被那些不理解它与柯里化之间微妙差别的人所迷惑,它们是不同的。部分函数应用可用于实现,但并不等同于柯里化。以下是来自关于区别的博客文章的一段话:
“部分应用将一个函数从中构建出一个接受更少参数的函数,而柯里化通过函数组合构建接受多个参数的函数,每个函数只接受一个参数。”
已经有人回答了这个问题,请参见此问题:如何在JavaScript函数调用中预设参数? 示例:
var fr = partial(f, 1, 2, 3);

// now, when you invoke fr() it will invoke f(1,2,3)
fr();

请查看那个问题以获取详细信息。


我需要为fr分配什么,才能使其在没有参数(fr())的情况下可调用,以便在调用fr时执行f(1,2,3)。 - Andreas Grech
5
未来读者请注意,在Jason的另一个回答中,请确保包含partial函数。 - KyleMit
2
作为 Jason 的 partial 函数的替代方案,UnderscoreJS 库也提供了一个 _.partial 函数。 - sfletche

2

您还可以重载Function原型:

// partially applies the specified arguments to a function, returning a new function
Function.prototype.curry = function( ) {
    var func = this;
    var slice = Array.prototype.slice;
    var appliedArgs = slice.call( arguments, 0 );

    return function( ) {
        var leftoverArgs = slice.call( arguments, 0 );
        return func.apply( this, appliedArgs.concat( leftoverArgs ) );
    };
};

// can do other fancy things:

// flips the first two arguments of a function
Function.prototype.flip = function( ) {
    var func = this;
    return function( ) {
        var first = arguments[0];
        var second = arguments[1];
        var rest = Array.prototype.slice.call( arguments, 2 );
        var newArgs = [second, first].concat( rest );

        return func.apply( this, newArgs );
    };
};

/*
e.g.

var foo = function( a, b, c, d ) { console.log( a, b, c, d ); }
var iAmA = foo.curry( "I", "am", "a" );
iAmA( "Donkey" );
-> I am a Donkey

var bah = foo.flip( );
bah( 1, 2, 3, 4 );
-> 2 1 3 4
*/

-5

下面的代码等价于您的第二个代码块:

var f = function () {
        //Some logic here...
    };

var fr = f;

fr(pars);

如果你想将一个函数的引用传递给另一个函数,可以像这样做:
function fiz(x, y, z) {
    return x + y + z;
}

// elsewhere...

function foo(fn, p, q, r) {
    return function () {
        return fn(p, q, r);
    }
}

// finally...

f = foo(fiz, 1, 2, 3);
f(); // returns 6

你几乎肯定最好使用一个框架来完成这种事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接