如何在JavaScript函数调用中预先设置参数? (部分功能应用)

时间:2008-11-26 15:33:11

标签: javascript functional-programming

我正在尝试编写一个JavaScript函数,该函数将返回其第一个参数(函数),其所有其余参数作为该函数的预设参数。

所以:

function out(a, b) {
    document.write(a + " " + b);
}

function setter(...) {...}

setter(out, "hello")("world");
setter(out, "hello", "world")();

两次输出“hello world”。对于setter的一些实现

我遇到了第一次尝试操作arguments数组的问题,但似乎有更好的方法来做到这一点。

8 个答案:

答案 0 :(得分:96)

首先,你需要一个部分 - there is a difference between a partial and a curry - 这就是你所需要的,没有框架

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

现在,使用您的示例,您可以完全按照以下方式执行操作:

partial(out, "hello")("world");
partial(out, "hello", "world")();

// and here is my own extended example
var sayHelloTo = partial(out, "Hello");
sayHelloTo("World");
sayHelloTo("Alex");

partial()函数可用于实现,但不是 currying。以下是a blog post on the difference的引用:

  

当部分应用程序接受一个函数并从中构建一个函数,该函数接受较少的参数,currying构建函数,这些函数通过函数组合获取多个参数,每个参数都采用一个参数。

希望有所帮助。

答案 1 :(得分:3)

curried javascript您要找的是什么?

答案 2 :(得分:2)

如果你使用Dojo,你只需调用几乎完全符合你想要的dojo.hitch()。差不多 - 因为它也可以用来打包上下文。但你的榜样是第一个:

dojo.hitch(out, "hello")("world");
dojo.hitch(out, "hello", "world")();

以及:

var A = {
  sep: ", ",
  out: function(a, b){ console.log(a + this.sep + b); }
};

// using functions in context    
dojo.hitch(A, A.out, "hello")("world");
dojo.hitch(A, A.out, "hello", "world")();

// using names in context
dojo.hitch(A, "out", "hello")("world");
dojo.hitch(A, "out", "hello", "world")();
dojo.hitch()是Dojo Base的一部分,所以只要你包含了dojo.js就可以了。

dojox.lang.functional.curry模块中提供了另一个常规工具(在Functional fun in JavaScript with Dojo中有记录 - 只需在此页面上查看“咖喱”)。具体来说,您可能需要查看curry()和partial()。

curry()累积参数(如在你的例子中),但有一点不同:只要arity满足,它就会调用返回值的函数。实现你的例子:

df.curry(out)("hello")("world");
df.curry(out)("hello", "world");

请注意,最后一行最后没有“()” - 它会自动调用。

partial()允许随机替换参数:

df.partial(out, df.arg, "world")("hello");

答案 3 :(得分:2)

使用Javascript' apply(),您可以修改function prototype

Function.prototype.pass = function() {
    var args = arguments,
        func = this;
    return function() {
        func.apply(this, args);
    }
};

然后,您可以将其称为out.pass('hello','world')

apply获取第二个参数/参数的数组。

arguments是函数内部可用的属性,它包含数组中的所有参数,如结构。

另一种常用方法是使用bind

loadedFunc = func.bind(this, v1, v2, v3);

然后

loadedFunc() === this.func(v1,v2,v3);

这有点足够,即使有点难看。

答案 4 :(得分:1)

您可以使用Function.prototype.bind()。这是ES5的补充。

除了设置函数的上下文(this值)的常用用例外,它还可以设置部分参数。

function out(a, b) {
  document.write(a + " " + b);
}

function setter(func) {
  return func.bind.apply(func, [window].concat([].slice.call(arguments).slice(1)));
}

setter(out, "hello")("world");
setter(out, "hello", "world")();

我的setter功能实际上非常简单。最长的部分是获取参数列表。我会像这样分解代码:

func.bind.apply(func, [window].concat([].slice.call(arguments).slice(1)))
func.bind.apply(                                                        )  // need to use apply to pass multiple arguments as an array to bind()
                func,                                                      // apply needs a context to be run in
                      [window].concat(                                 )   // pass an array of arguments to bind(), starting with window, to be the global context
                                      [].slice.call(arguments).slice(1)    // convert the arguments list to an array, and chop off the initial value

these browsers支持:Chrome 7 +,Firefox 4 +,IE9 +。 MDN(在开头链接)有一个polyfill。

答案 5 :(得分:0)

** 编辑:请参阅Jason Bunting的回复。这个答案实际上显示了链接众多调用的一种低级别的方式,而不是针对某些参数的预设的单个调用。如果这个答案实际上有助于解决类似的问题,你应该确保使用jason推荐的apply和call,而不是使用我想到的eval的模糊方法。 **

嗯......你的出局实际上会在这里写出“未定义”...但这应该接近你想要的:

function out(a, b) {
    document.write(a + " " + b);
}

function getArgString( args, start ) {
    var argStr = "";
    for( var i = start; i < args.length; i++ ) {
        if( argStr != "" ) {
            argStr = argStr + ", ";
        }
        argStr = argStr + "arguments[" + i + "]"
    }
    return argStr;
}

function setter(func) {
    var argStr = getArgString( arguments, 1 );
    eval( "func( " + argStr + ");" );
    var newSettter = function() {
        var argStr = getArgString( arguments, 0 );
        if( argStr == "" ) {
            argStr = "func";
        } else {
            argStr = "func, " + argStr;
        }
        return eval( "setter( " + argStr + ");" );
    }
    return newSettter;
}

setter(out, "hello")("world");
setter(out, "hello", "world")();

我可能会将getArgString中的代码移动到setter函数本身,但是因为我使用'eval'而稍微安全一些。

答案 6 :(得分:0)

在不立即调用函数的情况下(例如,在等待用户确认时)实现参数预设的简便方法是将函数“修饰”在另一个匿名函数中。

代替:exportFile(docType)

执行:function(){ return exportFile(docType) }

答案 7 :(得分:0)

使用闭包是另一种选择。使用返回其他函数的函数!