函数的作用域和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
版权声明:本文为博主原创文章,未经博主允许不得转载。