深入理解javascript之函数

页面导航:首页 > 网络编程 > JavaScript > 深入理解javascript之函数

深入理解javascript之函数

来源: 作者: 时间:2016-01-19 18:32 【

函数的作用域和this的指向我已经在前面的文章中讲过,今天主要讲讲函数的绑定。函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另外一个函数。该技巧常常和回调函

函数的作用域和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)+
);//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)+
);//8
var curriedAddB = curry(add,5,10);
document.write(curriedAddB()+
);//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

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

 

Tags:

文章评论

最 近 更 新
热 点 排 行
Js与CSS工具
代码转换工具

<