您的位置:首页 > Web前端 > JavaScript

深入理解javascript之函数

2015-08-04 10:15 309 查看
函数的作用域和this的指向我已经在前面的文章中讲过,今天主要讲讲函数的绑定。函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另外一个函数。该技巧常常和回调函数与事件处理程序一起使用,以便在将函数作为变量传递的同时保留函数的代码执行环境。

函数绑定

看下面的例子:

var handler = {
  message:"消息来了!",
  handlerClick :function(event){
    document.write(this.message);
  }
}
//一般的指定不能改变this的指向
var btn = document.getElementById("btn");
btn.addEventListener("click",handler.handlerClick,false);
//返回undefined 因为this的范围指向的是btn而不是hanlder


结果返回的是undefined,因为this的指向是btn这个DOM对象而不是hanlder,所以根本找不到handler.message。

所幸的是,我们可以通过一个闭包来解决这个问题。

//可以通过一个闭包来解决这个问题
btn.addEventListener("click",function(event){
  handler.handlerClick(event);
},false);
//返回 消息来了!,解决问题


但是用闭包始终不是一个好办法,因为过多的闭包会使代码变得不易调试和理解,所以我们可以利用apply来调整this的指向。接下来我们定义一个bind方法。

//但是过多的使用闭包并不是一个好办法,所以我们使用apply来改变this的指向
function bind(fn,context){
  return function(){
    return fn.apply(context,arguments);
  };
}
//通过自定义的bind方法来绑定事件
btn.addEventListener("click",bind(handler.handlerClick,handler),false);


这样就可以成功的将this的指向改变,这也是很多javascript第三方库绑定函数的方法。值得一提的是,ES5中自带就有bind方法,这样就不用我们再去自定义一个bind了:

//ES5中自带就有bind方法,就不需要我们自定义bind方法了。
//使用自带的bind方法
btn.addEventListener("click",handler.handlerClick.bind(handler),false);


函数柯里化

什么叫做函数柯里化呢?其实就是function currying的翻译。curry是咖喱的意思,呵呵。好了,回归正题,currying可以理解为就是用于创建已经设置好了一个或多个参数的函数。实现方法和函数绑定一样,都是通过闭包来返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。

//再来说说函数柯里化
//概念:用于创建已经设置好了一个或多个参数的函数,可以理解为函数中套函数
function add(num1,num2){
  return num1+num2;
}
function curriedAdd(num3){
  return add(5,num3);
}
document.write(add(2,3)+"<br>");//5
document.write(curriedAdd(3));//8
//上面的例子可以展示柯里化的概念


上面的例子虽然不是柯里化函数,但是可以展示其概念。下面我们介绍下创建函数柯里化的通用方法:

//下面介绍创建函数柯里化的通用方法
function curry(fn){
  var args = Array.prototype.slice.call(arguments,1);
  return function(){
    var innerArgs = Array.prototype.slice.call(arguments);
    var finalArgs = args.concat(innerArgs);//将innerArgs拼接到args后
    return fn.apply(null,finalArgs);
  }
}
//使用方法如下:
var curriedAdd = curry(add,5);
document.write(curriedAdd(3)+"<br>");//8
var curriedAddB = curry(add,5,10);
document.write(curriedAddB()+"<br>");//15
//可以看到参数灵活多变


也许看到这里,还不能够理解到底有什么作用,那么,我们可以将其和函数绑定结合起来,实现随意数量的传递参数:

//这样就可以在处理事件程序时传递其他参数了。
//比如下例子:,注意我们传入了name参数
var handlerB = {
  message:'消息来了!',
  handlerClick : function(name,event){
    document.write(this.message+":"+name);
  }
}
btn.addEventListener("click",curriedBind(handlerB.handlerClick,handler,'liufang'),false);//消息来了!:liufang


ES5中自带的bind方法同样已实现了柯里化,使用方法如下:

//ES5中的bind已经实现了柯里化,所以可以直接使用:
btn.addEventListener("click",handlerB.handlerClick.bind(handlerB,"liufangagain"),false);//消息来了!:liufangagain


函数绑定和函数柯里化提供了强大的动态函数功能,它们可以用于创建复杂的算法和功能,但是会带来额外的开销。

本文全部实例地址: demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: