10

以下代码有效,虽然我理解它为什么有效,但我在任何地方都没有看到它。我认为这是因为所有其他设计模式都好得多。

我仍然希望将这个例子视为一个警示故事,但我没有。

当然,这很糟糕,尤其是下面我选择的示例,因为它的作用很清楚,但是:

这种模式叫什么?

是常用的吗?

有没有使用这种模式的合法项目?

var add = function container (val) {

  addFunc = function f (val, undefined) {
  addFunc.total += val;
  return addFunc;
  };

addFunc.total = 0;

return addFunc(val);
};

alert(add(1)(2)(3).total);
alert(add(1)(2)(33).total);

编辑:变量名称更改,以便代码在 IE 中工作。

4

4 回答 4

4

这是一个称为currying的函数式编程概念。

本质上,给定 afunction foo(a, b, c)你创建一个function bar(a)返回function bar2(b)的返回function bar3(c)给出最终答案的返回。

从技术上讲,这不是真正的柯里化,因为它无限地进行并使用副作用(total属性)来打破无限循环。

但无论如何,这种模式可能会有一些有用的应用。它对于遍历树结构特别有用,在这种结构中,您要为树的每个叶子计算一些结果,结果取决于该叶子的祖先。您在根节点上运行 curried 函数,然后在每个子节点上运行返回的函数,然后对每个子节点等运行。如果运行的节点有子节点,纯 curried 函数将返回另一个函数,并且如果您到达叶子,将返回所需的值。

代码将是一个简单的递归函数,它向自身传递一个新的“根”节点和解析它的函数,它总是接受一个参数。

但是,这里使用它的方式看起来更像是一种学习练习,而不是有用的东西。

编辑:如果你想让它成为一个纯柯里化函数但仍然具有准无限递归,则输入数据需要提供停止信息(就像 C 字符串使用值0x00来定义一样EOF):

var add = (function() {
    var total = 0;
    return function nextAdd(a) {
        if(a != null) {
            total += a;
            return nextAdd;
        } else {
            return total;
        }
    };
})();

然后,add(1)(2)(3)(null) === 6没有.total副作用参数。

于 2012-04-17T16:17:16.690 回答
4

从技术上讲,这可以被认为是链接或封装。

当您可以无限期地执行一组操作时,您可以链接原始功能。当您可以链接调用以设置原始选择器的属性和属性时,jQuery 使用这种形式。在这种情况下,创建者希望能够链接调用 add 而不必重新键入函数名称。不是最干净的想法,但有效。

此外,由于代码的实际主体从未暴露给调用者,因此这也可以视为封装,因为该addFunc方法没有暴露给外部范围。

于 2012-04-17T15:54:37.143 回答
1

这被称为柯里化维基百科。来自 Haskell Curry维基百科的名称(但最初由 Moses Ilyich Schönfinkel维基百科开发)。

一种转换具有多个参数(或参数的 n 元组)的函数的技术,使得它可以被称为一个函数链,每个函数都有一个参数(部分应用)。

来自2010 年的 JavaScript 模式

何时使用柯里化 - 当你发现自己调用相同的函数并传递大部分相同的参数时,那么该函数可能是柯里化的一个很好的候选者。您可以通过将一组参数部分应用于您的函数来动态创建一个新函数。新函数将保存重复的参数(因此您不必每次都传递它们)并将使用它们来预填充原始函数期望的完整参数列表。

来自达斯汀迪亚兹的另一篇关于咖喱的文章。

于 2012-04-17T16:13:43.020 回答
1

你会变得更好:

function add() {
    var l = arguments.length, i, sum = 0;
    for( i=0; i<l; i++) sum += arguments[i];
    return sum;
}
alert(add(1,2,3)); // 6

确实,您所询问的代码样式应该没有理由。我没有看到任何合法的使用,只有任意arguments长度。

于 2012-04-17T15:54:51.060 回答