2011-02-13 25 views
153

docs我知道.proxy()會改變作爲參數傳遞的函數的作用域。有人能解釋我更好嗎?我們爲什麼要這樣做?

+1

根據該文件,「這個方法對於將事件處理程序附加到上下文指向不同對象的元素時最有用。此外,jQuery確保ev如果你綁定從jQuery.proxy()返回的函數,它仍然會解除正確的函數,如果傳遞了原來的「。有沒有什麼特別的你覺得缺乏的措辭? – bzlm 2011-02-13 19:36:46

+1

這裏還不清楚另外,jQuery確保即使你綁定從jQuery.proxy()返回的函數,它仍然會解除綁定正確的函數,如果通過原始的「。原來的意思是什麼? – 2011-02-13 19:46:49

+0

原來是這樣的但是由於你沒有完全掌握這些東西,你確定需要使用它嗎? – bzlm 2011-02-13 19:55:26

回答

351

它最終做的是確保函數中的this的值將成爲您期望的值。

一個常見的例子是setTimeout發生在click處理程序中。

藉此:

$('#myElement').click(function() { 
     // In this function, "this" is our DOM element. 
    $(this).addClass('aNewClass'); 
}); 

的意圖是很簡單的。當單擊myElement時,它應該得到類aNewClass。在處理程序this內部表示被點擊的元素。

但是如果我們在添加類之前需要短暫的延遲,該怎麼辦?我們可以使用setTimeout來完成它,但麻煩在於,無論我們給setTimeout的函數,該函數內的值this將是window而不是我們的元素。

$('#myElement').click(function() { 
    setTimeout(function() { 
      // Problem! In this function "this" is not our element! 
     $(this).addClass('aNewClass'); 
    }, 1000); 
}); 

所以,我們能做些什麼,而不是,是調用$.proxy(),它發送的功能,我們要分配給this的值,它會返回將保留值的函數。

$('#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的價值,它返回一個函數,將確保this設置正確。

它是如何做到的?它只是返回一個匿名函數,使用.apply()方法調用我們的函數,它可以明確設置值this

簡化看時返回可能看起來像功能:

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,和所有它是用正確的this上下文中執行我們原來的功能。

46

沒有進入更詳細地(因爲這是ECMAScript中大約上下文這將是必要的,在此上下文變量等)

有三種不同類型的「上下文」在ECMA-/使用Javascript:

  • 全球背景
  • 功能方面
  • EVAL方面

每個代碼都在其執行上下文中執行。有一個全局上下文,並且可能有許多函數(和eval)上下文的實例。現在有趣的部分:

函數的每次調用都會進入函數執行上下文。函數的執行上下文的樣子:

啓動對象
作用域鏈
這個值

所以值是與執行相關的特殊對象上下文。有在ECMA-/ JavaScript的兩個功能可以在一個函數執行上下文改變值:通過調用

.call() 
.apply() 

如果我們有一個功能foobar()我們可以改變這個

foobar.call({test: 5}); 

現在我們可以在foobar訪問我們傳遞的對象:

function foobar() { 
    this.test // === 5 
} 

這正是jQuery.proxy()所做的。它需要一個functioncontext(它不過是一個對象),並通過調用.call().apply()來鏈接該函數並返回該新函數。

4

我寫了這個功能:

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); } 
} 
0

同樣的目標可以用自執行的函數來實現:

$('#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>