有人可以帮我写和理解部分应用模式吗?

时间:2015-04-22 05:51:34

标签: javascript function functional-programming higher-order-functions partial-application

我试图使用会模仿此行为的回调来编写函数:

var fullName = function (firstName, lastName) {
  return firstName + ' ' + lastName;
};

var michaelName = partial(fullName, 'Michael');
michaelName('Moore'); // 'Michael Moore'
michaelName('Jackson'); // 'Michael Jackson'

我被困了一段时间试图编写一个名为partial的函数,该函数将回调函数fullName,但最终让它工作但不确定它是否正确#) b)到底发生了什么。

var partial = function(callback, firstName) {
    var innerFunction = function(lastName) { //I declared an inner function in order to create a closure of the variable lastName
      return callback(firstName, lastName); //The closure is completed (or is it only then created?) by returning the function argument named callback taking firstName and lastName as arguments
    };
    return innerFunction; //the function partial will finally return the closure, function innerFunction
}

var michaelName = partial(fullName, 'Michael');
console.log(michaelName('Moore')); //Michael Moore

我在定义函数partial时编写回调的一般模式是什么?如果没有,有人可以显示/指出我可以学习这种模式的地方吗?有没有其他方法可以重构这个回调,以便它更干净?我不确定是否需要创建一个新的innerFunction,但是当我这样做时,我终于让行为按预期工作了。我对代码的评论中的推理是否准确?有人会介意踩过我的代码并进一步解释发生的事情,为什么callbackinnerFunction返回,为什么partial会返回innerFunction而不是callback?很有责任。

3 个答案:

答案 0 :(得分:3)

是的,您已经写过partial功能完全正确。

我会通过使用术语"回调"来避免让自己感到困惑。这里。该单词通常用于不同的上下文中:表示在完成某事时调用的例程,或者例如由forEach为数组的每个元素调用的例程。在这里,你传入的只是一个底层函数,当调用返回的函数时,它将与一个额外的指定参数一起调用。您也可以直接返回该功能,只需

var partial = function(fn, firstName) {
    return function(lastName) {
        return fn(firstName, lastName);
    };
}
  

有没有其他方法可以重构此回调以使其更清晰?

不是真的,除了上面提到的。但是,它可以更加通用(见下文)。

  

我不确定是否需要创建新的innerFunction,但是当我这样做时,我终于让行为按预期工作。

根据定义,partial需要返回一个函数。这就是它的目的。所以是的,你必须创建你要返回的功能。您可以将其创建为单独的命名函数,然后像往常一样将其返回,或者在return语句中创建它,如上所述。

  

我对代码的评论中的推理是否准确?

不完全:

  

我声明了一个内部函数,以便创建变量lastName

的闭包

但实际上这个函数正在关闭firstName,这是来自外部范围的变量。

  

通过返回名为callback的函数参数将firstName和lastName作为参数

来完成闭包(或者只是创建它?)

不同的人对关闭的确切含义有不同的看法。有人会说仅仅使用外部范围的变量定义函数就构成了一个闭包。其他人会说它不是一个闭包,或者至少将它称为闭包是没有意义的,除非该功能是"导出" (返回)从外面使用,就像你一样。

  

有人会介意踩过我的代码并进一步解释发生了什么,为什么callbackinnerFunction返回,为什么partial会返回innerFunction而不是callback }?

callback未从innerFunction返回;它的结果是调用。这正是您需要它的工作方式:您希望partial返回的函数调用您最初传入的函数。直接从callback返回partial将无法完成任何操作;你只需要返回传入的函数。

所以整体流程是:

  1. 你有一些像fullName这样的函数,你想要创建另一个函数,其中第一个参数"已填入"。

  2. 定义函数partial,它接受​​一个函数来填充参数,以及要填充的参数。

  3. partial"记得"要调用的函数和传入的参数传递给它。它返回一个函数(这是你想要的)

  4. 您调用从partial返回的部分函数,​​该函数使用预填充参数调用原始函数,并将另一个函数传递给该函数。该功能(您的innerFunction)可以"看到"要调用的函数(你称之为callback)和要填充的参数,因为关闭它们(它是从外部范围访问这些变量的闭包。

  5. 但是,你的偏见有点受限。首先,它只处理一个预先填充的参数。您可能想要处理更多。此外,它还不知道如何通过this传递给innerFunction。您可以通过以下方式解决这些问题:

    function partial(fn, ...prefilledArgs) {
        return function(...additionalArgs) {
            return fn.call(this, ...prefilledArgs, ...additionalArgs);
        };
    }
    

    在上面,我使用了新的ES6"传播参数"功能,因为它更容易阅读和写。在ES5中,您需要使用数组函数将预先填充的参数和其他参数拼接在一起,这不是太有趣,如下所示:

    function partial(fn)
        var prefilledArgs = Array.prototype.slice.call(arguments, 1);
        return function() {
            var additionalArgs = Array.prototype.slice.call(arguments);
                return fn.apply(this, prefilledArgs.concat(additionalArgs));
        };
    }
    

    在上面,我们记得"通过使用prefilledArgs删除参数伪数组的第一个元素(fn),将预填充的参数分配给变量slice。然后,在内部函数内部,我们连接预先填充的参数和附加参数,并使用apply将整个列表传递给原始函数,这是在有参数时调用函数的方法。阵列。

答案 1 :(得分:1)

如果您正在寻找一种更清晰的方式来编写代码,我建议您使用Javascript闭包。这是一个解释closures的链接。

   var partial = function( firstName) {
       return function(lastName) { 
          return firstName + " " + lastName
        };
    }

    var michaelName = partial('Michael');
    console.log(michaelName('Moore'));

如果你需要更好地理解回调,Youtube有一些很棒的视频,这里有一个帮助我理解Callbacks的叠加帖子。

帖子的引用

  

简单来说,回调函数就像是“调用”的工人   当他完成任务时回到他的经理。

答案 2 :(得分:1)

虽然您的评论不是很正确,但您已经了解了我所理解的模式。这是一个更通用的实现:

var partial = function(fn) {
    var appliedArgs = Array.prototype.slice.call(arguments,1);
    return function() {
        var moreArgs = Array.prototype.slice.call(arguments);
        return fn.apply(this,appliedArgs.concat(moreArgs));
    }
}

这与你的主要区别在于它允许传入的函数(callback,在你的)中有任意数量的参数,并允许部分应用程序满足任意数量的那些...只要它们按顺序应用。

(请注意,MDN docs建议不要那样切片arguments ......同时也提供了这样做的示例。那里没有双重消息!)

好的,让我们逐步介绍你的例子:

首先,您声明基本函数 - fullName()。那里没有混乱。这个函数有两个参数。部分应用程序的有用之处在于,您可能会发现自己处于一个您现在知道某些参数的位置,但直到稍后才知道其他参数。部分应用程序允许您立即应用一些参数(因此部分应用程序'),获取与基本功能具有相同效果的函数,但需要更少的参数(因为您已经提供其他人。)

接下来,您拨打电话var michaelName = partial(fullname,"Michael");您在这里要求的是"给我一个名为michaelName的新功能,它可以执行fullName如果第一个参数始终是' Michael'我只需要给它起一个姓氏"。一旦你理解了这一点,其余的代码就开始变得有意义了。

partial()必须返回一个函数,而不是一个简单的值,因为这是你要求的 - 一个新的,更简单的你传入的回调版本。那应该是什么功能呢?如果用“迈克尔”调用它,它应该给出回调结果。以及它给出的第二个功能。

再次执行您的实施:

var partial = function(callback, firstName) {
    var innerFunction = function(lastName) { 
      return callback(firstName, lastName);
    };
    return innerFunction; 
}

这正是innerFunction()的确切含义。它是一个功能,可将已知的firstName和新的lastName提供给callback(),然后返回结果。