定义和用法
$.proxy 方法接受一个已有的函数,并返回一个带特定上下文的新的函数。
该方法通常用于向上下文指向不同对象的元素添加事件。
提示:如果您绑定从 $.proxy 返回的函数,jQuery 仍然可以通过传递的原先的函数取消绑定正确的函数。
语法 1
语法 2
参数 | 描述 |
---|---|
function | 要被调用的已有的函数。 |
context | 函数所在的对象的名称。 |
name | 已有的函数,其上下文将被改变(应该是 context 对象的属性)。 |
<!DOCTYPE html>
<html>
<head>
<script src="http://libs.baidu.com/jquery/1.10.2/jquery.min.js">
</script>
<script>
$(document).ready(function(){
var objPerson = {
name: "John Doe",
age: function(){
$("p").after("Name:age " + this.name);
}
test: function(){
$("p").after("Name: " + this.name );
}
};
$("button").click($.proxy(objPerson,"test"));
});
</script>
</head>
<body>
<button>Run test function</button>
<p></p>
</body>
</html>
JQuery.proxy(function,context):
使用context代替function中的context。
比如:
var you = {
type: "person",
test: function(event) {
$("#log").append( this.type + " " );
}
$("#test").click(you.test);调用这句只有相当于调用:
$("#test").click(function(event){
$("#log").append( this.type + " " );
});
所以这里的this指的是$("#test").
如果这样调用:$("#test").click($.proxy(you.test,you));
此时的调用相当于:
$("#test").click(function(event){
$("#log").append( you.type + " " );
});
虽然调用事件的对象是$("#test"),但是却可以使用$.proxy把事件执行内的对象改变为you。
JQuery.proxy(context,functionname):
第一个参数是你想proxy的对象,第二个参数为要改变的函数的名字。
var obj = {
name: "John",
test: function() {
$("#log").append( this.name );
$("#test").unbind("click", obj.test);
}
};
$("#test").click( jQuery.proxy( obj, "test" ) ); 把obj作为context传入test中,而不是$("#test").
这个执行完之后,结果会是John,
如果使用下面这句
$("#test").click(obj.test);
结果会是$("#test").的name值。
这个函数和上面的那个函数的功能一样,就是使用了更加简洁的方式。
最后附上一篇stackoverflow的一个关于Porxy的一个问答的答案。问答原地址:http://stackoverflow.com/questions/4986329/understanding-proxy-in-jquery
What it ultimately does is it ensures that the value of this in a function will be the value you desire.
A common example is in a setTimeout that takes place inside a click handler.
Take this:
$('#myElement').click(function() {
// In this function, "this" is our DOM element.
$(this).addClass('aNewClass');
});
The intention is simple enough. When myElement is clicked, it should get the class aNewClass. Inside the handler this represents the element that was clicked.
But what if we wanted a short delay before adding the class? We might use a setTimeout to accomplish it, but the trouble is that whatever function we give to setTimeout, the value of thisinside that function will be window instead of our element.
$('#myElement').click(function() {
setTimeout(function() {
// Problem! In this function "this" is not our element!
$(this).addClass('aNewClass');
}, 1000);
});
So what we can do instead, is to call $.proxy(), sending it the function and the value we want to assign to this, and it will return a function that will retain that value.
$('#myElement').click(function() {
// ------------------v--------give $.proxy our function,
setTimeout($.proxy(function() {
$(this).addClass('aNewClass'); // Now "this" is again our element
}, this), 1000);
// ---^--------------and tell it that we want our DOM element to be the
// value of "this" in the function
});
So after we gave $.proxy() the function, and the value we want for this, it returned a function that will ensure that this is properly set.
How does it do it? It just returns an anonymous function that calls our function using the .apply()method, which lets it explicitly set the value of this.
A simplified look at the function that is returned may look like:
function() {
// v--------func is the function we gave to $.proxy
func.apply( ctx );
// ----------^------ ctx is the value we wanted for "this" (our DOM element)
}
So this anonymous function is given to setTimeout, and all it does is execute our original function with the proper this context.
jQuery.proxy(),接受一个函数,然后返回一个新函数,并且这个新函数始终保持了特定的上下文(context )语境。
-
jQuery.proxy( function, context )
function将要改变上下文语境的函数。
context函数的上下文语境(`this`)会被设置成这个 object 对象。
-
jQuery.proxy( context, name )
context函数的上下文语境会被设置成这个 object 对象。
name将要改变上下文语境的函数名(这个函数必须是前一个参数 ‘context’ 对象的属性)
这个方法通常在向一个元素上附加事件处理函数时,上下文语境实际是指向另一个对象的情况下使用。
另外,jQuery 能够确保即使你绑定的函数是经过 jQuery.proxy() 处理过的函数,你依然可以用原先的函数来正确地取消绑定。
看一下官方的例子:
var obj = { name: "John", test: function() { alert( this.name ); $("#test").unbind("click", obj.test); } }; $("#test").click( jQuery.proxy( obj, "test" ) ); // 以下代码跟上面那句是等价的: // $("#test").click( jQuery.proxy( obj.test, obj ) ); // 可以与单独执行下面这句做个比较。 // $("#test").click( obj.test );
可以看一下jQuery中的实现(1.6之前的版本):
/* jQuery 源码之 proxy: 使用 apply 形式, 执行回调函数. */ jQuery.proxy = function( fn, proxy, thisObject ) { if ( arguments.length === 2 ) { // jQuery.proxy(context, name); if ( typeof proxy === "string" ) { thisObject = fn; fn = thisObject[ proxy ]; proxy = undefined; /* 转化结果: thisObject -> context fn -> name proxy -> undefined */ } // jQuery.proxy(name, context); else if ( proxy && !jQuery.isFunction( proxy ) ) { thisObject = proxy; proxy = undefined; } } if ( !proxy && fn ) { /* 使用 proxy 保证 函数执行时, context 为指定值 */ proxy = function() { return fn.apply( thisObject || this, arguments ); }; } // Set the guid of unique handler to the same of original handler, so it can be removed if ( fn ) { proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; } // So proxy can be declared as an argument return proxy; }
其实就是平常使用的的call和apply,大部分的时候作为回调使用。
在stackoverflow上有个问题,其中的例子比较典型,供参考:
比如有如下代码:
$('#myElement').click(function() { // In this function, "this" is our DOM element. $(this).addClass('aNewClass'); });
这里的this就是我们的DOM元素。如果我们要在增加class样式之前需要等待一段时间,可能会将代码写成下面这样(注意:有问题的代码):
$('#myElement').click(function() { setTimeout(function() { // Problem! In this function "this" is not our element! $(this).addClass('aNewClass'); }, 1000); });
这里的this就不是我们期望的那个DOM元素了。解决方法就是使用jQuery的$.proxy()了,代码如下:
$('#myElement').click(function() { // ------------------v--------give $.proxy our function, setTimeout($.proxy(function() { $(this).addClass('aNewClass'); // Now "this" is again our element }, this), 1000); // ---^--------------and tell it that we want our DOM element to be the // value of "this" in the function });
我们可以这样来理解上面的代码:
function() { // v--------func is the function we gave to $.proxy func.apply( ctx ); // ----------^------ ctx is the value we wanted for "this" (our DOM element) }
这就体现出来jQuery中$.proxy()的强大功效了。
在某些情况下,我们调用Javascript函数时候,this指针并不一定是我们所期望的那个。例如:
1 //正常的this使用 2 $('#myElement').click(function() { 3 4 // 这个this是我们所期望的,当前元素的this. 5 6 $(this).addClass('aNewClass'); 7 8 }); 9 10 11 //并非所期望的this 12 $('#myElement').click(function() { 13 14 setTimeout(function() { 15 16 // 这个this指向的是settimeout函数内部,而非之前的html元素 17 18 $(this).addClass('aNewClass'); 19 20 }, 1000); 21 22 });
这时候怎么办呢,通常的一种做法是这样的:
1 $('#myElement').click(function() { 2 var that = this; //设置一个变量,指向这个需要的this 3 4 setTimeout(function() { 5 6 // 这个this指向的是settimeout函数内部,而非之前的html元素 7 8 $(that).addClass('aNewClass'); 9 10 }, 1000); 11 12 });
但是,在使用了jquery框架的情况下, 有一种更好的方式,就是使用$.proxy函数。
jQuery.proxy(),接受一个函数,然后返回一个新函数,并且这个新函数始终保持了特定的上下文(context )语境。
有两种语法:
jQuery.proxy( function, context ) /**function将要改变上下文语境的函数。 ** context函数的上下文语境(`this`)会被设置成这个 object 对象。 **/ jQuery.proxy( context, name ) /**context函数的上下文语境会被设置成这个 object 对象。 **name将要改变上下文语境的函数名(这个函数必须是前一个参数 ‘context’ **对象的属性) **/
上面的例子使用这种方式就可以修改成:
$('#myElement').click(function() { setTimeout($.proxy(function() { $(this).addClass('aNewClass'); }, this), 1000); });