理解jQuery中的$ .proxy()?
从docs我明白, .proxy()
将改变作为parameter passing函数的范围。 有人可以更好地解释我,我们为什么要这样做?
它最终做的是确保this
函数的价值将成为你所期望的价值。
一个常见的例子是在click
处理程序中发生的setTimeout
。
拿着它:
$('#myElement').click(function() { // In this function, "this" is our DOM element. $(this).addClass('aNewClass'); });
意图很简单。 当myElement
被点击时,它应该得到类aNewClass
。 处理程序内部表示被点击的元素。
但是如果我们想在join课程之前想要短暂的延迟呢? 我们可能使用setTimeout
来完成它,但麻烦的是,无论我们给setTimeout
的函数, this
函数内部的值将是window
而不是我们的元素。
$('#myElement').click(function() { setTimeout(function() { // Problem! In this function "this" is not our element! $(this).addClass('aNewClass'); }, 1000); });
所以我们可以做的就是调用$.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 });
所以在给了$.proxy()
这个函数和我们想要的值之后,它返回了一个函数来确保this
函数被正确设置。
它是如何做到的? 它只是返回一个匿名函数,它使用.apply()
方法调用我们的函数,它可以明确地设置这个值。
返回函数的简化看起来可能如下所示:
function() { // v--------func is the function we gave to $.proxy func.apply( ctx ); // ----------^------ ctx is the value we wanted for "this" (our DOM element) }
所以这个匿名函数给了setTimeout
,它所做的就是用适当的上下文执行我们原来的函数。
没有进入更多的细节(这将是必要的,因为这是关于ECMAScript中的上下文 , 这个上下文variables等)
在ECMA- / Javascript中有三种不同types的“上下文”:
- 全球背景
- 函数上下文
- 评估上下文
每个代码都在其执行上下文中执行 。 有一个全局上下文,函数(和eval)上下文可以有很多实例。 现在有趣的部分:
每个函数调用都会进入函数执行上下文。 函数的执行上下文如下所示:
激活对象
范围链
这个值
所以这个值是一个与执行上下文相关的特殊对象。 在ECMA- / Javascript中有两个函数可以在函数执行上下文中改变这个值:
.call() .apply()
如果我们有一个函数foobar()
我们可以调用这个值来调用:
foobar.call({test: 5});
现在我们可以在foobar
访问我们传入的对象:
function foobar() { this.test // === 5 }
这正是jQuery.proxy()
所做的。 它需要一个function
和context
(除了一个对象之外的东西),并通过调用.apply()
或.apply()
链接函数并返回这个新函数。
我写了这个函数:
function my_proxy (func,obj) { if (typeof(func)!="function") return; // If obj is empty or another set another object if (!obj) obj=this; return function () { return func.apply(obj,arguments); } }
使用自动执行function可以达到同样的目标:
$('#myElement').click(function() { (function(el){ setTimeout(function() { // Problem! In this function "this" is not our element! el.addClass('colorme'); }, 1000); })($(this)); // self executing function });
.colorme{ color:red; font-size:20px; }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <script src="https://code.jquery.com/jquery-3.1.0.js"></script> <div id="myElement">Click me</div> </body> </html>