Mengapa mendefinisikan fungsi anonim dan meneruskannya ke jQuery sebagai argumen?

96

Saya sedang melihat-lihat kode demo kode intip yang sangat baik dari screencasts backbone.js. Di dalamnya, kode tulang punggung semuanya tertutup dalam fungsi anonim yang diteruskan objek jQuery:

(function($) {
  // Backbone code in here
})(jQuery);

Dalam kode tulang punggung saya sendiri, saya baru saja membungkus semua kode saya di acara 'siap' jQuery DOM:

$(function(){
  // Backbone code in here
});

Apa poin / keuntungan dari pendekatan pertama? Melakukannya dengan cara ini membuat fungsi anonim yang kemudian dieksekusi segera dengan objek jQuery diteruskan sebagai argumen fungsi, yang secara efektif memastikan bahwa $ adalah objek jQuery. Apakah ini satu-satunya poin - untuk menjamin bahwa jQuery terikat ke '$' atau adakah alasan lain untuk melakukan ini?

Matt Roberts
sumber
4
Anda seharusnya melihat SO terlebih dahulu.
Alexander
Interoperabilitas dengan pustaka lain - jika pembuat halaman perlu menggunakan $.noConflict(), contoh pertama masih akan berfungsi.
DCoder
Kemungkinan duplikat: jQuery dan $ pertanyaan
Alexander
Lihat kemungkinan duplikat dokumen jQuery .ready vs self calling anonymous function untuk perbedaannya
Bergi
@Alexander tetapi kemudian orang lain akan menemukan pertanyaan ini di SO terlebih dahulu. :-)
caiosm1005

Jawaban:

179

Dua blok kode yang telah Anda tunjukkan sangat berbeda dalam kapan dan mengapa mereka dieksekusi. Mereka tidak eksklusif satu sama lain. Mereka tidak melayani tujuan yang sama.

Modul JavaScript


(function($) {
  // Backbone code in here
})(jQuery);

Ini adalah pola "Modul JavaScript", diimplementasikan dengan fungsi pemanggilan langsung.

Tujuan kode ini adalah untuk memberikan "modularitas", privasi, dan enkapsulasi untuk kode Anda.

Implementasi ini adalah fungsi yang langsung dipanggil oleh (jQuery)tanda kurung pemanggil . Tujuan meneruskan jQuery ke dalam tanda kurung adalah untuk memberikan cakupan lokal ke variabel global. Ini membantu mengurangi jumlah overhead saat mencari $variabel, dan memungkinkan kompresi / pengoptimalan yang lebih baik untuk minifier dalam beberapa kasus.

Fungsi pemanggilan segera dijalankan, yah, segera. Segera setelah definisi fungsi selesai, fungsi tersebut dijalankan.

Fungsi "DOMReady" jQuery

Ini adalah alias untuk fungsi "DOMReady" jQuery: http://api.jquery.com/ready/


$(function(){
  // Backbone code in here
});

Fungsi "DOMReady" jQuery dijalankan ketika DOM siap untuk dimanipulasi oleh kode JavaScript Anda.

Modul vs DOMReady Dalam Kode Backbone

Ini bentuk yang buruk untuk mendefinisikan kode Backbone Anda di dalam fungsi DOMReady jQuery, dan berpotensi merusak kinerja aplikasi Anda. Fungsi ini tidak akan dipanggil sampai DOM telah dimuat dan siap untuk dimanipulasi. Itu berarti Anda menunggu hingga browser mengurai DOM setidaknya satu kali sebelum Anda mendefinisikan objek.

Sebaiknya tentukan objek Backbone di luar fungsi DOMReady. Saya, di antara banyak lainnya, lebih suka melakukan ini di dalam pola Modul JavaScript sehingga saya dapat memberikan enkapsulasi dan privasi untuk kode saya. Saya cenderung menggunakan pola "Revealing Module" (lihat tautan pertama di atas) untuk memberikan akses ke bit yang saya butuhkan di luar modul saya.

Dengan menentukan objek Anda di luar fungsi DOMReady, dan menyediakan beberapa cara untuk mereferensikannya, Anda mengizinkan browser untuk memulai pemrosesan JavaScript Anda, berpotensi mempercepat pengalaman pengguna. Itu juga membuat kode lebih fleksibel karena Anda dapat memindahkan banyak hal tanpa harus khawatir membuat lebih banyak fungsi DOMREady saat Anda benar-benar memindahkan sesuatu.

Anda kemungkinan akan tetap menggunakan fungsi DOMReady, meskipun Anda mendefinisikan objek Backbone di tempat lain. Alasannya adalah banyak aplikasi Backbone perlu memanipulasi DOM dengan cara tertentu. Untuk melakukan ini, Anda perlu menunggu sampai DOM siap, oleh karena itu Anda perlu menggunakan fungsi DOMReady untuk memulai aplikasi Anda setelah itu telah ditentukan.

Anda dapat menemukan banyak contohnya di web, tetapi berikut ini adalah implementasi yang sangat mendasar, menggunakan baik Module dan fungsi DOMReady:



// Define "MyApp" as a revealing module

MyApp = (function(Backbone, $){

  var View = Backbone.View.extend({
    // do stuff here  
  });

  return {
    init: function(){
      var view = new View();
      $("#some-div").html(view.render().el);
    }
  };

})(Backbone, jQuery);



// Run "MyApp" in DOMReady

$(function(){
  MyApp.init();
});
Derick Bailey
sumber
1
Terima kasih atas tanggapan mendetail ini. Saya tahu tentang fungsi DOMReady hanya memanggil saat peristiwa siap DOM diaktifkan, tetapi tidak pernah benar-benar berpikir itu akan menjadi masalah. Memisahkan kode menjadi mendefinisikan bit tulang punggung di dalam modul, dan kemudian berinteraksi dengannya dalam siap dom memang tampak seperti pendekatan terbaik
Matt Roberts
2
Menariknya, aplikasi contoh "rencana" dengan backbone src menempatkan semuanya di dom ready.
Matt Roberts
2
Jangan lupa pola modul javascript juga disebut IIFE.
Jess
1
fungsi anonim pada dasarnya dijalankan pada saat yang sama dengan DOM siap jadi bagaimana membuatnya lebih efisien ??
bhavya_w
14

Sebagai catatan kecil, mengirim $ sebagai argumen ke fungsi anonim membuat $ lokal ke fungsi itu yang memiliki implikasi kinerja positif kecil jika fungsi $ disebut banyak. Ini karena javascript mencari ruang lingkup lokal untuk variabel terlebih dahulu dan kemudian melintasi semua jalan ke lingkup jendela (di mana $ biasanya berada).

joidegn.dll
sumber
9

Ini memastikan Anda selalu dapat menggunakan $di dalam penutupan itu bahkan jika $.noConflict()digunakan.

Tanpa penutupan ini, Anda seharusnya menggunakannya, jQuerybukan $sepanjang waktu.

ThiefMaster
sumber
4

Ini untuk menghindari potensi konflik dari variabel $. Jika sesuatu yang lain mendefinisikan variabel bernama $, plugin Anda mungkin menggunakan definisi yang salah

Lihat http://docs.jquery.com/Plugins/Authoring#Getting_Started untuk detail selengkapnya

Andrew Brock
sumber
2

Gunakan keduanya.

Fungsi pemanggilan mandiri di mana Anda meneruskan jQuery untuk mencegah konflik perpustakaan, dan untuk memastikan jQuery tersedia seperti yang Anda harapkan dengan $.

Dan metode pintasan .ready () yang diperlukan untuk menjalankan javascript hanya setelah DOM dimuat:

(function($) {
    $(function(){
          //add code here that needs to wait for page to be loaded
    });

    //and rest of code here
})(jQuery);
Andrew
sumber
Versi yang lebih pendek yang saya temukan di tempat lain di SO (juga melindungi yang tidak ditentukan) :jQuery(function ($, undefined) { /* Code */ });
Jared Gotte