w3ctech

JavaScript闭包详解【2】

本文翻译自《Secrets_of_the_JavaScript_Ninja》 本文由小豪翻译

之前在交流会上,和杜欢讨论过闭包的一些小东西,这里的文章主要还是从闭包产生的结果切人,讲述闭包的一些妙用,不探讨闭包产生的原因

函数参数的嵌入

函数参数的嵌入技术,原文是"Partially Applying Functions",是一种在函数执行前,对其增加参数的方法。事实上,这个方法让你调用了一个新的函数。

注:assert是qunit单元测试所用的方法,第一个参数若为true则输出第二个参数,通常true表示执行结果为预期的值,下面都用到了assert对结果进行校验

String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = ("John, Resig, Boston").csv();
assert( results[1] == "Resig", "字母切分成功" );

partial方法就是能够实现partially apply的函数,我们可以看到虽然csv在调用的时候没有带任何参数,但是还是按照/,\s*/进行split了。

prototype框架里有一个curry函数,和partial比较类似。

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变量和args变量保存下来,并可以让返回的函数能够访问到,在返回的函数中,我们将本身的参数和保存下的args参数进行合并,也就做到了嵌入参数的功能。

curry函数看起来很妙,但是我们还可以做的更好。如果我们需要将一些参数保留给可能传入的函数,那么就需要做一些更多的处理。

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 &amp;&amp; arg < arguments.length; i++ )
   if ( args[i] === undefined )
    args[i] = arguments[arg++];
  return fn.apply(this, args);
 };
};

我们通过将预设参数中的undefine值替换为传入的函数,从而实现了一个更方便的参数嵌入函数。看几个实用的例子。

//delay函数的实现
var delay = setTimeout.partial(undefined, 10);
delay(function(){
 assert( true, "函数延迟调用成功" );
});
//事件绑定的实现
var bindClick = document.body.addEventListener
 .partial("click", undefined, false);
bindClick(function(){
 assert( true, "当前函数绑定了click事件" );
});

这个技术的主要目的函数缩小代码的复杂度,让API的使用更加方便清晰。

对闭包的产生和原理感兴趣的同学,可以看下http://www.otakustay.com/closure-ppt/。

w3ctech微信

扫码关注w3ctech微信公众号

共收到0条回复