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

javascript中的函数绑定

2015-10-27 14:11 656 查看
首先我们来看看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指向对象obj
proxy(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]));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: