JQuery'de $ .proxy () yöntemini anlama


167

Gönderen docs Anlıyorum .proxy()argüman olarak iletilen fonksiyonun kapsamını değiştirecektir. Birisi bana bunu daha iyi açıklayabilir mi? Bunu neden yapalım?


1
Belgelere göre, "Bu yöntem, bağlam işleyicilerini içeriğin farklı bir nesneye işaret ettiği bir öğeye eklemek için en kullanışlıdır. Ayrıca, jQuery, jQuery.proxy () öğesinden döndürülen işlevi bağlasanız bile orijinali geçtiyse hala doğru işlevi ayırın ". Eksik bulduğunuz ifadeyle ilgili özel bir şey var mı?
bzlm

1
Bu burada net değil Ayrıca, jQuery, jQuery.proxy () 'den döndürülen işlevi bağlasanız bile, orijinali geçtiğinde yine de doğru işlevi çözeceğini garanti eder. - Orijinalin anlamı nedir?
Aditya Shukla

Orijinal, bir proxy için oluşturulmuş olanıdır. Ancak bu şeyleri tam olarak anlamadığınız için, onu kullanmanız gerektiğinden emin misiniz?
bzlm

1
İşte $ .proxy'nin nasıl çalıştığını gösteren nettuts tarafından hazırlanmış harika bir video eğitimi. http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-learning-jquery-1-4s-proxy/
Hüseyin

1
@bzlm, ben bu yöntem geldi jquery belgeleri okuyordu.
Aditya Shukla

Yanıtlar:


381

Sonuçta yaptığı şey this, bir fonksiyondaki değerin arzu ettiğiniz değer olmasını sağlamaktır.

Yaygın bir örnek, setTimeoutbir clickişleyicinin içinde yer alan bir örnektir .

Bunu al:

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

Niyet yeterince basit. Ne zaman myElementtıklandığında, bu sınıf almalısınız aNewClass. İşleyicinin içinde thistıklanan öğeyi temsil eder.

Ama ya dersi eklemeden önce kısa bir gecikme isteseydik? Bunu setTimeoutbaşarmak için a'yı kullanabiliriz , ama sorun şu ki setTimeout, verdiğimiz fonksiyon ne olursa olsun , thisbu fonksiyonun içindeki değerin windowelemanımız yerine olması.

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

Bunun yerine, yapabileceğimiz, $.proxy()onu atamak istediğimiz işlevi ve değeri göndererek çağırmaktır ve bu değeri thiskoruyacak bir işlev döndürür.

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

Bu nedenle $.proxy(), işlevi ve istediğimiz değeri verdikten sonra , düzgün bir şekilde ayarlanmasını thissağlayacak bir işlev döndürdü this.

Bunu nasıl yapıyor? Sadece açıkça değerini ayarlamasını sağlayan yöntemi kullanarak fonksiyonumuzu çağıran anonim bir fonksiyon döndürür ..apply()this

Döndürülen işleve basitleştirilmiş bir görünüm şöyle görünebilir:

function() {
    // v--------func is the function we gave to $.proxy
    func.apply( ctx );
    // ----------^------ ctx is the value we wanted for "this" (our DOM element)
}

Yani bu anonim işleve verilir setTimeoutve tüm yaptığı şey orijinal fonksiyonumuzu uygun thisbağlamda yürütmektir .


Kullanmak $.proxy(function () {...}, this)yerine kullanmanın değeri nedir (function() {...}).call(this)? Bir fark var mı?
Justin Morgan

11
@ JustinMorgan: .callsizinle fonksiyonu hemen çağırıyorsunuz. İle $.proxy, Function.prototype.bindyeni bir işlev döndürdüğü yere benzer . Bu yeni işlevin thisdeğeri kalıcı olarak bağlıdır, böylece iletildiğinde setTimeoutve setTimeoutişlevi daha sonra çağırdığında yine de doğru thisdeğere sahip olur.
gri devlet

2
Varsa, bu tekniğin böyle bir şeye göre avantajı nedir? $ ('# myElement'). click (function () {var el = $ (this); setTimeout (function () {el.addClass ('aNewClass');}, 1000);});
Greg

1
Bu örnek için $ .proxy yöntemini kullanmanız gerekmez. Bunun yerine, bu $ ('# myElement') gibi yeniden yazabilirsiniz. Tıklayın (function () {var that = this; setTimeout (function () {/ / $ işleyici yöntemi kapsamında bildirilen bir değişken aracılığıyla yeni bağlam (o) .addClass ('aNewClass');}, 1000);});
paul

4
112k temsilcisi, korkunç iyi JavaScript / jQuery bilgisi olan ve Ekim 2011'den beri görülmeyen anonim bir kullanıcı ... John Resig belki de?
cantera

49

Daha fazla ayrıntıya girmeden ( ECMAScript'teki Bağlam , bu bağlam değişkeni vb . İle ilgili olduğu için gerekli olacaktır )

ECMA- / Javascript'te üç farklı tür "Bağlam" vardır:

  • Küresel bağlam
  • İşlev bağlamı
  • değerlendirme bağlamı

Her kod yürütme bağlamında yürütülür . Tek bir küresel bağlam vardır ve birçok işlev (ve değerlendirme) bağlamı örneği olabilir. Şimdi ilginç kısım:

Bir işlevin her çağrılması işlev yürütme bağlamına girer. Bir işlevin yürütme bağlamı şöyle görünür:

Aktivasyon Nesnesi
Kapsam Zinciri
bu değer

Dolayısıyla bu değer, yürütme bağlamıyla ilgili özel bir nesnedir. ECMA- / Javascript içinde bir işlev yürütme bağlamında bu değeri değiştirebilecek iki işlev vardır :

.call()
.apply()

Bir fonksiyonumuz varsa foobar(), bu değeri arayarak değiştirebiliriz:

foobar.call({test: 5});

Şimdi geçtiğimiz foobarnesneye erişebildik :

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

Aynen jQuery.proxy()öyle. Bir functionve context(bir nesneden başka bir şey değildir) alır ve işlevi çağırarak .call()veya .apply()bu yeni işlevi döndürerek işlevi bağlar .


1
Mükemmel açıklama, fonksiyon için resmi jQuery dokümanlarından daha basit / daha iyi
Higuaro

4

Bu işlevi yazdım:

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

1

Aynı hedefe "Hemen Başlatılan İşlev İfadesi, kısa: IIFE" kendi kendini yürütme işlevi kullanılarak da ulaşılabilir :

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


2
Genellikle "Derhal-çağrılan Fonksiyon İfade" yerine bir "kendini infaz fonksiyonu" den (Hayatta) denir Yani, bkz en.wikipedia.org/wiki/Immediately-invoked_function_expression .
Chris Seed
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.