Memahami $ .proxy () di jQuery

167

Dari dokumen saya mengerti bahwa .proxy()akan mengubah ruang lingkup fungsi yang dilewatkan sebagai argumen. Bisakah seseorang tolong jelaskan saya ini lebih baik? Kenapa kita harus melakukan ini?

Aditya Shukla
sumber
1
Menurut dokumentasi, "Metode ini paling berguna untuk melampirkan pengendali acara ke elemen di mana konteksnya menunjuk kembali ke objek yang berbeda. Selain itu, jQuery memastikan bahwa bahkan jika Anda mengikat fungsi yang dikembalikan dari jQuery.proxy () itu akan masih melepas ikatan fungsi yang benar, jika melewati yang asli ". Adakah sesuatu yang khusus tentang ungkapan yang menurut Anda kurang?
bzlm
1
Ini tidak jelas di sini. Selain itu, jQuery memastikan bahwa meskipun Anda mengikat fungsi yang dikembalikan dari jQuery.proxy () itu masih akan melepaskan ikatan fungsi yang benar, jika melewati yang asli ". Apa yang dimaksud dengan yang asli?
Aditya Shukla
Yang asli adalah yang dibuat proxy. Tetapi karena Anda tidak sepenuhnya memahami hal-hal ini, apakah Anda yakin perlu menggunakannya?
bzlm
1
Berikut ini adalah video tutorial hebat dari nettuts yang menunjukkan cara kerja $ .proxy. http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-learning-jquery-1-4s-proxy/
Hussein
1
@ bzlm, saya sedang membaca dokumentasi jquery ketika saya menemukan metode ini.
Aditya Shukla

Jawaban:

381

Apa yang akhirnya dilakukan adalah memastikan bahwa nilai thisdalam suatu fungsi akan menjadi nilai yang Anda inginkan.

Contoh umum adalah dalam setTimeoutyang terjadi di dalam clickpawang.

Ambil ini:

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

Niatnya cukup sederhana. Ketika myElementdiklik, itu harus mendapatkan kelas aNewClass. Di dalam pawang thismewakili elemen yang diklik.

Tetapi bagaimana jika kita ingin penundaan singkat sebelum menambahkan kelas? Kita mungkin menggunakan a setTimeoutuntuk mencapainya, tetapi masalahnya adalah bahwa fungsi apa pun yang kita berikan setTimeout, nilai thisdi dalam fungsi itu akan windowbukan elemen kita.

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

Jadi yang bisa kita lakukan sebagai gantinya adalah memanggil $.proxy(), mengirimkannya fungsi dan nilai yang ingin kita tetapkan this, dan itu akan mengembalikan fungsi yang akan mempertahankan nilai itu.

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

Jadi setelah kami memberikan $.proxy()fungsi, dan nilai yang kami inginkan this, mengembalikan fungsi yang akan memastikan bahwa thisdiatur dengan benar.

Bagaimana cara melakukannya? Itu hanya mengembalikan fungsi anonim yang memanggil fungsi kami menggunakan .apply()metode, yang memungkinkannya secara eksplisit mengatur nilai this.

Tampilan yang disederhanakan pada fungsi yang dikembalikan mungkin terlihat seperti:

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

Jadi fungsi anonim ini diberikan setTimeout, dan semua yang dilakukannya adalah menjalankan fungsi asli kami dengan thiskonteks yang tepat .

pengguna113716
sumber
Apa nilai dari menggunakan $.proxy(function () {...}, this)daripada (function() {...}).call(this)? Apakah ada perbedaan?
Justin Morgan
11
@JustinMorgan: dengan .callAnda memanggil fungsi segera. Dengan $.proxy, itu seperti di Function.prototype.bindmana ia mengembalikan fungsi baru. Fungsi baru itu memiliki thisnilai yang terikat secara permanen, sehingga ketika diteruskan ke setTimeout, dan setTimeoutmemanggil fungsi nanti, ia akan tetap memiliki nilai yang benar this.
negara abu
2
Apa untungnya, jika ada, teknik ini dibandingkan sesuatu seperti ini? $ ('# myElement') .klik (function () {var el = $ (this); setTimeout (function () {el.addClass ('aNewClass');}, 1000);});
Greg
1
Anda tidak harus menggunakan metode $ .proxy untuk contoh ini. Sebaliknya, Anda cukup menulis ulang seperti $ ini ('# myElement'). Klik (function () {var that = this; setTimeout (function () {/ / konteks baru melalui variabel yang dideklarasikan dalam ruang lingkup metode handler $ (itu) .addClass ('aNewClass');}, 1000);});
paul
4
Pengguna anonim dengan tenaga 112k, pengetahuan JavaScript / jQuery yang menakutkan, dan belum pernah terlihat sejak Oktober 2011 ... John Resig mungkin?
cantera
49

Tanpa masuk ke detail yang lebih besar (yang diperlukan karena ini adalah tentang Konteks dalam ECMAScript, variabel konteks ini, dll.)

Ada tiga jenis "Konteks" dalam ECMA- / Javascript:

  • Konteks global
  • Konteks fungsi
  • konteks eval

Setiap kode dieksekusi dalam konteks eksekusi . Ada satu konteks global dan ada banyak contoh konteks fungsi (dan eval). Sekarang bagian yang menarik:

Setiap panggilan fungsi masuk ke konteks eksekusi fungsi. Konteks eksekusi dari suatu fungsi terlihat seperti:

Aktivasi Obyek
Lingkup Rantai
nilai ini

Jadi nilai ini adalah objek khusus yang terkait dengan konteks eksekusi. Ada dua fungsi dalam ECMA- / Javascript yang dapat mengubah nilai ini dalam konteks eksekusi fungsi:

.call()
.apply()

Jika kami memiliki fungsi, foobar()kami dapat mengubah nilai ini dengan memanggil:

foobar.call({test: 5});

Sekarang kita bisa mengakses foobarobjek yang kita lewati:

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

Inilah tepatnya yang jQuery.proxy()dilakukannya. Dibutuhkan a functiondan context(yang tidak lain adalah objek) dan menautkan fungsi dengan memanggil .call()atau .apply()mengembalikan fungsi baru tersebut.

jandy
sumber
1
Penjelasan luar biasa, lebih sederhana / lebih baik daripada dokumen resmi jQuery untuk fungsi ini
higuaro
4

Saya telah menulis fungsi ini:

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); }
}
sgv_test
sumber
1

Tujuan yang sama dapat dicapai dengan menggunakan "Segera-dipanggil Fungsi Ekspresi, singkat: Iife" fungsi mengeksekusi diri :

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

Legenda
sumber
2
Itu biasanya disebut "Ekspresi Fungsi Segera-Dibawa" (IIFE) daripada "fungsi self-executing", lihat en.wikipedia.org/wiki/Immediately-invoked_function_expression .
Chris Seed