javascript中的函数绑定

来源:互联网 发布:道尔顿新华公学 知乎 编辑:程序博客网 时间:2024/05/22 02:30

首先我们来看看jQuery中的proxy函数如何实现函数绑定的:

   proxy: function( fn, context ) {var args, proxy, tmp;//这说明:在直接调用proxy得到新的函数的时候就可以传入多余的参数,从第三个参数以后会被当作额外的参数来处理args = slice.call( arguments, 2 );proxy = function() {//这里的arguments就是真正函数调用的时候传入的参数,通过把两次的参数结合调用最终返回的函数!return fn.apply( context || this, args.concat( slice.call( arguments ) ) );};return proxy;}
例子1:

//在当前页面内追加换行标签和指定的HTML内容function w( html ){document.body.innerHTML += "<br/>" + html;}var name = "Hello";function foo( a, b,c,d ){w( this.name );w( a + b+c+d );}var obj = { name: "CodePlayer", age: 18 };var proxy = $.proxy( foo, obj, 5, 10 );//调用proxy函数的时候返回了一个新的函数,该函数的context就是obj,同时因为他是通过闭包完成,所以他会得到外层的args也就是调用,$.proxy时候传入的多余的参数!同时通过闭包也能够访问外层的参数的fn!// 代理调用foo()函数,此时其内部的this指向对象objproxy(5,6);// CodePlayer// 26
例子2:

var handler={message:"event handle",handleCick:function(event){alert(this.message);}}var btn=document.getElementById("button");//这时候打印"undefined",因为这里面的this指向了button对象,在IE8中会指向window//buttom对象没有message属性,所以打印undefined!btn.onclick=handler.handleCick;
note:在IE8中会指向window,其它浏览器指向button!
例子3:(重点不是闭包,而是修正this,this在这里的指向就是调用者handler)

var handler={message:"event handle",handleCick:function(event){alert(this.message);}}//那么为什么说这句话修改了this呢,因为this指向的就是调用者!而在这个函数中调用者就是handler//至于为什么把event传入到handleClick中,是因为在handleClick中可以获取到这个事件的具体信息!var btn=document.getElementById("button");btn.onclick=function(event){handler.handleCick(event);}
note:例子2和例子3都是针对特定代码进行绑定对象修正的,不具有共性,从而才引入了函数绑定的概念!
例4:

   function show(n1,n2){ alert(n1); alert(n2); alert(this);}$.proxy(show ,document,3,4)();//直接用括号调用$.proxy(show,document,3)(4);//调用的时候传入4作为参数
note:上面两种调用方式都是相等的,this指向了document对象。其实在jQuery的源码中处处有函数绑定的影子,下面就是在$.when函数中的代码片段

.done( updateFunc( i, resolveContexts, resolveValues ) )
note:对于特定的Deferred对象,我们在他的回调集合中加入了updateFunc方法调用后的结果,这个结果也是一个函数,而这个返回的函数可以访问updateFunc函数中的所有的参数信息!如i,resolveContexts,resolveValues等!当你用resolve方法传入参数的时候就会被传递到updateFunc调用返回的新的参数中作为arguments!

例5:原生的ECMAScript5的bind方法

 调用者是一个函数,参数是一个对象,表示将这个函数绑定到这个参数中,从而在这个函数中可以用this访问这个参数对象!

var handler={message:"event handle",handleCick:function(event){alert(this.message);}}var btn=document.getElementById("button");//这时候就会打印"event handle"btn.onclick=handler.handleCick.bind(handler);//主要用于事件处理程序,setTimeout,setInterval,然而和普通函数相比//有更多的内存开销,而且因为是多重函数调用稍微慢一点!
例6:

其实关于关于bind方法的博客是很多的,但是从他们对bind的描述来说我们可以知道,bind方法和上面的proxy函数内部具有相似的逻辑。拿着这个函数作为下次真正调用时候执行,把bind时候传入的多于一个的参数作为局部变量args保存下来,然后把它和返回新函数调用的参数组合起来,作为新的参数传入到新函数中!

var slice=Array.prototype.slice;//返回的是一个本地call方法,这个call方法的上下文是slice方法//如果你给这个本地call方法传入参数,那么这个参会会被送到原生的call方法中去执行!var nativeCall=Function.prototype.call.bind(slice);//打印true,这个nativeCall方法的上下文是slice方法!alert(nativeCall({0:"xx",1:"ccc"}) instanceof Array);
下面这个例子的本地call方法的上下文就是concat方法(要调用谁的方法就把谁作为上下文):

var concat=Array.prototype.concat;//返回的是一个本地call方法,这个call方法的上下文是slice方法//如果你给这个本地call方法传入参数,那么这个参会会被送到原生的call方法中去执行!var nativeCall=Function.prototype.call.bind(concat,[1,2,3]);//打印true,这个nativeCall方法的上下文是slice方法!alert(nativeCall([4,5,6]));

0 0
原创粉丝点击