偏应用函数
“分部应用”一个函数是一项特别有趣的技术,在函数调用之前,我们可以预先传入一些函数。实际上,偏应用函数返回了一个含有预处理参数的新函数,以便后期可以调用。
这类代理函数--代理的是另外一个函数,并且在执行的时候会调用所代理的函数。
这种在一个函数中首先填充几个参数(然后再返回一个新函数)的技术称之为柯里化(curring)。
柯里化函数示例(在第一个特定参数中进行填充)
1 2 3 4 5 6 7 8 9
| Function.prototype.curry = function() { //该函数以及预填充的参数是保存在闭包中的 var fn = this, args = Array.prototype.slice.call(arguments); //创建一个匿名柯里化函数 return function(){ return fn.apply(this,args.concat(Array.prototype.slice.call(arguments))); }; }
|
这种技术是另外一个利用闭包记住状态的很好例子。在本例中,我们要记住新增加的函数(这里的this参数不会存在于任何闭包中,因为每个函数调用的时候都有自己的this)以及预填充参数,并将它们转移到新创建的函数中。该新函数将有预填充的参数以及刚传入的新参数。其结果就是,这样的方法可以让我们预先传入一些参数,然后返回给我们一个新的简单函数供我们使用。
虽然这种风格的分部函数非常有用,但我们可以做的更好。如果我们给特定函数传递遗漏的参数,而不是从参数列表一开始就传。
一个更复杂的”分部”函数
1 2 3 4 5 6 7 8 9 10 11 12
| Function.prototype.partial = function() { var fn = this, args = Array.prototype.slice.call(arguments); return function(){ var arg = 0; for (var i=0; i < args.length && arg < arguments.length; i++) { if (args[i] === undefined) { args[i] = arguments[arg++]; } } return fn.apply(this, args); }; }
|
该实现的本质类似于Prototype的curry()方法,但它有几个重要的差异。值得注意的是,用户可以在参数列表的任意位置指定参数,然后在后续的调用中,根据遗漏的参数值是否等于undefined来判断参数的遗漏,要实现这种功能,我们添加了参数合并功能。很有效果,遍历传入的所有参数参数,判断相应的参数是否遗漏了(是否是undefined),然后沿着顺序填充遗漏的参数。
1 2 3 4 5
| var delay = setTimeout.partial(undefined, 10); delay(function(){ assert(true, "A call to this function will be delayed 10 ms."); });
|
这段代码创建了一个新的函数,名为delay(),通过该函数,我们可以传入另外一个10毫秒后进行调用的异步函数。
我们也可以创建一个简单的函数用于事件绑定:
1 2 3 4 5
| var bindClick = document.body.addEventListener.partial("click", undefined, false); bindClick(function(){ assert(true, "Click event bound via curried function"); });
|