问题 add(1)(2)(3).total === 6 - 有没有其他人看过这样的自回归函数? [关闭]


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

我仍然希望看到这个例子作为沿线的警示故事,但我没有。

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

这种模式叫什么?

它常用吗?

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

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中工作。


7250
2018-04-17 15:50


起源

这个设计模式看起来像拼图而不是干净的代码:) - Eugene Retunsky
但为什么你会做那样的事情?! - Aleks G
这种模式对我来说似乎并不可怕。阅读非常清楚。我想我宁愿看到 total 作为局部变量,和 .total property作为返​​回结果的方法,并重置变量。
@ user989370:为什么?对你有什么特别令人反感的?我不知道代码怎么会更清楚。
@amnotiam - 我很高兴,清楚是我写这个例子的目的。这不是我所看到的,它是由于我做的一个错字而产生的,我写了这个例子,因为它很容易遵循。<br />我认为我的主要反对意见是:我什么时候才能使用它? <br />关于可读性,我们有:<br /> add(1)(2)(3)vs add(1).add(2).add(3)vs add(1,2,3)。虽然add(1,2,3)在简洁方面胜出,但我喜欢add(1)(2)(3),因为在更复杂的例子中很明显它是3个单独的操作按顺序完成而不是一个函数使用3参数。 - user989370


答案:


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

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

此外,由于代码的实际主体永远不会暴露给调用者,因此也可以将其视为封装 addFunc 方法不暴露在外部范围内。


4
2018-04-17 15:54



我是创造者 - 我并没有真正创造它的目的,它是一个错字的结果我清理成一个工作的例子,但你说的其余的完美。我没想到它首先这样说,我希望它有一个名字,一些流行音乐,比如“自我调用的匿名函数” - 有一个你不会忘记的名字。 - user989370
我忘记了:我之前已经看过方法链接(并且我喜欢它在jQuery中)并且我理解它为什么有效,我大多试图理解为什么这样而不是另一个。 - user989370


这是一个函数式编程概念 柯里

基本上,给定一个 function foo(a, b, c) 你创造了一个 function bar(a) 返回 function bar2(b) 返回 function bar3(c) 给出了最终答案。

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

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

代码将是一个简单的递归函数,它向自己传递一个新的“根”节点和用它来解析它的函数,它总是需要一个参数。

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

编辑:如果你想使它成为一个纯粹的currying函数但仍然具有准无限递归,输入数据需要提供停止信息(就像一个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 副作用参数。


4
2018-04-17 16:17



由于整个代码可以替换为1 + 2 + 3 - 它绝对不是这样使用的,这只是为了表明它实际运行。 - user989370
嘿,刚刚添加了一个纯粹的加法版本的加法器供你查看。 - David Ellis
感谢这个例子 - .total部分最后用螺栓固定在我的例子上,表明它有效,但实际上还没有计划好 - 我主要是为了提高速度而且具有一定的可读性。我想我会进一步研究,因为这似乎是从这里到现实世界的代码的飞跃。 - user989370
现在我想到了,你所做的也与概念有关 懒惰的评价。 - David Ellis


这叫做Currying 维基百科。来自Haskell Curry的名字 维基百科 (但最初是由MosesIlyichSchönfinkel开发的 维基百科 )。

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

JavaScript模式 表格2010:

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

另一个 咖喱的文章 来自Dustin Diaz。


2
2018-04-17 16:13





你可以通过以下方式获得无限好处:

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 长度。


1
2018-04-17 15:54



我认为最明显的改进是 - 1 + 2 + 3。显然我用它的例子只是说明而不是任何人都会做的事情(我希望!)。我真的没有用它,也没有用过它。 - user989370