Apa tujuan dari fungsi self executing di javascript?

427

Dalam javascript, kapan Anda ingin menggunakan ini:

(function(){
    //Bunch of code...
})();

lebih dari ini:

//Bunch of code...
Ej.
sumber
3
Lihat juga penjelasan ( teknis ) dan di sini . Untuk sintaks, lihat mengapa tanda kurung diperlukan dan ke mana mereka harus pergi .
Bergi
Mengapa ia memiliki dua tanda kurung terakhir, tepat sebelum titik koma?
johnny
3
@ Johnny bagian sebelum dua kurung terakhir menyatakan fungsi (anonim). Kedua tanda kurung memanggil fungsi.
Ej.
7
"Ekspresi Fungsi Segera Diminta" atau IIFE adalah nama yang lebih baik untuk ini.
Flimm

Jawaban:

404

Ini semua tentang pelingkupan variabel. Variabel yang dideklarasikan dalam fungsi self-executing, secara default, hanya tersedia untuk kode dalam fungsi self-executing. Ini memungkinkan kode ditulis tanpa memperhatikan bagaimana variabel dinamai dalam blok kode JavaScript lainnya.

Misalnya, seperti yang disebutkan dalam komentar oleh Alexander :

(function() {
  var foo = 3;
  console.log(foo);
})();

console.log(foo);

Ini pertama-tama akan mencatat 3dan kemudian melemparkan kesalahan pada berikutnya console.logkarena footidak ditentukan.

Ken Browning
sumber
7
Dan juga untuk kepentingan banyak orang di luar sana termasuk sejumlah Netflix Engineers: ITU HANYA FUNGSI. Ini tidak dengan sendirinya mewakili penutupan. Kadang-kadang auto-invokers digunakan bersama dengan skenario penutupan-relevan untuk melakukan hal-hal yang rapi, tetapi jika Anda tidak melihat sesuatu berpegangan pada referensi yang akan dikumpulkan dan dibuang dalam bahasa non-penutupan, itu tidak ada artinya freaking lakukan dengan PENUTUPAN.
Erik Reppen
2
Jadi ini artinya, sebagian besar digunakan dengan penutupan?
Pir Abdul
@AlexanderBird, tidak benar ... jika Anda melakukannya tanpa var, seperti ini ...function(){ foo=3;}:? Itu akan mengatur variabel global, kan?
T.Todua
2
@AlexanderBird tapi itu sudah terjadi dalam variabel lokal di dalam fungsi: function(){ var foo = 3; alert(foo); }; alert(foo);Jadi saya masih belum mengerti
João Pimentel Ferreira
Ah, saya mengerti, Anda mencapai ketiga fitur ini sekaligus: 1) Anda menjalankan fungsinya dengan hanya mendeklarasikannya; 2) Sebagai fungsi apapun, ruang lingkup variabel hanya lokal; dan 3) Fungsi ini mungkin anonim, tidak mencemari ruang lingkup utama
João Pimentel Ferreira
94

Sederhana. Terlihat sangat normal, hampir menghibur:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

Namun, bagaimana jika saya menyertakan pustaka javascript yang sangat berguna ke halaman saya yang menerjemahkan karakter tingkat lanjut ke dalam representasi level dasar mereka?

Tunggu apa?

Maksud saya, jika seseorang mengetik karakter dengan beberapa aksen di atasnya, tetapi saya hanya ingin karakter 'Bahasa Inggris' AZ di program saya? Nah ... karakter Spanyol 'ñ' dan Prancis 'é' dapat diterjemahkan ke dalam karakter dasar 'n' dan 'e'.

Jadi seseorang yang baik telah menulis konverter karakter komprehensif di luar sana yang dapat saya sertakan di situs saya ... saya sertakan.

Satu masalah: ia memiliki fungsi di dalamnya yang disebut 'nama' sama dengan fungsi saya.

Inilah yang disebut tabrakan. Kami memiliki dua fungsi yang dideklarasikan dalam lingkup yang sama dengan nama yang sama. Kami ingin menghindari ini.

Jadi kita perlu mengatur kode kita.

Satu-satunya cara untuk memasukkan kode lingkup dalam javascript adalah dengan membungkusnya dalam suatu fungsi:

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Itu mungkin memecahkan masalah kita. Semuanya sekarang tertutup dan hanya dapat diakses dari dalam kurung buka dan tutup kami.

Kami memiliki fungsi dalam suatu fungsi ... yang aneh untuk dilihat, tetapi sepenuhnya legal.

Hanya satu masalah. Kode kami tidak berfungsi. Variabel userName kami tidak pernah bergema ke konsol!

Kami dapat mengatasi masalah ini dengan menambahkan panggilan ke fungsi kami setelah blok kode yang ada ...

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

Atau sebelumnya!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Masalah kedua: Apa peluang nama 'utama' belum digunakan? ... sangat, sangat ramping.

Kami membutuhkan LEBIH pelingkupan. Dan beberapa cara untuk secara otomatis menjalankan fungsi utama () kami.

Sekarang kita sampai pada fungsi eksekusi otomatis (atau menjalankan sendiri, menjalankan sendiri, apa pun).

((){})();

Sintaksinya canggung sebagai dosa. Namun, itu berhasil.

Ketika Anda membungkus definisi fungsi dalam tanda kurung, dan termasuk daftar parameter (set atau tanda kurung lain!) Itu bertindak sebagai panggilan fungsi .

Jadi mari kita lihat kode kita lagi, dengan beberapa sintaks yang dijalankan sendiri:

(function main() {
  var userName = "Sean";

    console.log(name());

    function name() {
      return userName;
    }
  }
)();

Jadi, di sebagian besar tutorial yang Anda baca, Anda sekarang akan dibombardir dengan istilah 'pelaksana mandiri anonim' atau yang serupa.

Setelah bertahun-tahun pengembangan profesional, saya sangat menyarankan Anda untuk memberi nama setiap fungsi yang Anda tulis untuk keperluan debugging.

Ketika terjadi kesalahan (dan itu akan terjadi), Anda akan memeriksa backtrace di browser Anda. Itu selalu lebih mudah untuk mempersempit masalah kode Anda ketika entri dalam jejak tumpukan memiliki nama!

Sangat bertele-tele dan saya harap ini membantu!

Sean Holden
sumber
2
Terima kasih :) Saya sedang mencari di internet untuk memahami manfaat IIFE dalam kaitannya dengan fungsi normal dalam hal privasi variabel dan jawaban Anda adalah yang terbaik. Semua orang mengatakan bahwa salah satu keuntungan terbaik adalah bahwa variabel dan fungsi di dalam IIFE bersifat 'akhirnya' pribadi ketika fungsi normal hanya memberi Anda hal yang persis sama. Akhirnya saya pikir saya mendapatkannya melalui proses penjelasan Anda. Lagipula IIFE hanyalah fungsi, tetapi sekarang saya mengerti mengapa harus menggunakannya. Terima kasih lagi!
viery365
Terima kasih telah meluangkan waktu untuk menjelaskan ini dengan baik.
MSC
Jawaban bagus. Saya punya pertanyaan tentang poin terakhir Anda, - Ketika Anda merekomendasikan semua fungsi diberi nama, apakah Anda mengatakan ada cara untuk melakukan itu dengan fungsi self-executing, atau menyarankan agar semua orang memberi nama fungsi lalu menyebutnya? EDIT Oh, begitu. Yang ini sudah bernama. Duh. Mungkin ingin menunjukkan bahwa Anda membenarkan penggunaan Anda atas fungsi yang dijalankan sendiri.
FireSBurnsmuP
Ya teman saya, ini adalah jawaban yang saya cari:)
João Pimentel Ferreira
Ini adalah jawaban yang saya cari, bukan jawaban yang ditandai diterima. Apakah saya benar mengatakan bahwa ini bukan tentang tumbukan nama variabel , tetapi tentang tumbukan nama fungsi ? Variabel dalam fungsi non-iife yang normal bahkan dicakup secara lokal dan tidak bertabrakan dengan variabel global, bukan?
Kumar Manish
32

Doa diri (juga dikenal sebagai doa otomatis) adalah ketika suatu fungsi dieksekusi segera setelah definisinya. Ini adalah pola inti dan berfungsi sebagai dasar bagi banyak pola pengembangan JavaScript lainnya.

Saya penggemar berat :) karena:

  • Ini membuat kode menjadi minimum
  • Ini menegakkan pemisahan perilaku dari presentasi
  • Ini memberikan penutupan yang mencegah konflik penamaan

Sangat - (Kenapa kamu harus mengatakan yang baik?)

  • Ini tentang mendefinisikan dan menjalankan fungsi sekaligus.
  • Anda bisa memiliki fungsi yang menjalankan sendiri mengembalikan nilai dan meneruskan fungsi sebagai param ke fungsi lain.
  • Ini bagus untuk enkapsulasi.
  • Ini juga baik untuk pelingkupan blok.
  • Ya, Anda dapat melampirkan semua file .js Anda dalam fungsi self-executing dan dapat mencegah polusi namespace global. ;)

Lebih lanjut di sini .

MA Hossain Tonu
sumber
43
Poin 1. Bagaimana? Poin 2. Itu dari praktik terbaik yang sama sekali berbeda. Butir 3. Fungsi apa yang tidak? 4,5,6,7. Relevansi? 8. Yah, 1/8 tidak buruk kurasa.
Erik Reppen
2
Tujuh tahun terlambat tetapi, untuk poin 1. tidak mengurangi kode sama sekali, bahkan menambahkan minimal dua baris kode dalam menciptakan fungsi.
YungGun
1
satu-satunya titik di sini adalah "Ini memberikan penutupan yang mencegah konflik penamaan", setiap titik lainnya adalah penulisan ulang ini atau salah. mungkin Anda bisa menyederhanakan jawaban Anda?
pcarvalho
19

Penempatan nama. Lingkup JavaScript adalah tingkat fungsi.

Christoph
sumber
7
downvotes masih datang karena saya menggunakan namespacing instad dari scoping ; ini adalah masalah definisi - lihat misalnya Wikipedia : Namespace dalam ilmu komputer (kadang-kadang juga disebut lingkup nama), adalah wadah abstrak atau lingkungan yang dibuat untuk mengadakan pengelompokan logis dari pengidentifikasi atau simbol unik (yaitu, nama). dan Pengidentifikasi namespace dapat memberikan konteks (Cakupan dalam ilmu komputer) untuk sebuah nama, dan istilah tersebut kadang-kadang digunakan secara bergantian.
Christoph
5
Lingkup tingkat fungsi Javascript menyediakan ruang tempat nama variabel hidup, sebuah namespace ; bahwa itu adalah anonim yang tidak terkait dengan pengidentifikasi namespace tidak relevan ...
Christoph
12

Saya tidak percaya bahwa tidak ada jawaban yang menyebutkan global tersirat.

The (function(){})()konstruk tidak melindungi terhadap GLOBALS tersirat, yang bagi saya adalah perhatian yang lebih besar, lihat http://yuiblog.com/blog/2006/06/01/global-domination/

Pada dasarnya blok fungsi memastikan semua "global vars" yang Anda definisikan terbatas pada program Anda, itu tidak melindungi Anda dari mendefinisikan global implisit. JSHint atau sejenisnya dapat memberikan rekomendasi tentang cara mempertahankan diri dari perilaku ini.

var App = {}Sintaks yang lebih ringkas memberikan tingkat perlindungan yang sama, dan dapat dibungkus dalam blok fungsi saat berada di halaman 'publik'. (lihat Ember.js atau SproutCore untuk contoh perpustakaan nyata yang menggunakan konstruk ini)

Sejauh privateproperti pergi, mereka agak berlebihan kecuali jika Anda membuat kerangka kerja publik atau perpustakaan, tetapi jika Anda perlu mengimplementasikannya, Douglas Crockford memiliki beberapa ide bagus.

David W. Keith
sumber
8
Mode ketat melindungi terhadap global yang tersirat. Itu bersama dengan penyerang otomatis akan Anda liput. Saya tidak pernah mengerti kehebohan atas properti pribadi. Deklarasikan vars di dalam construct constructor. Selesai Jika pikiran lupa menggunakan kata kunci 'baru' membuat Anda terjaga di malam hari, tulislah fungsi pabrik. Selesai lagi.
Erik Reppen
8

Saya sudah membaca semua jawaban, sesuatu yang sangat penting hilang di sini , saya akan KISS. Ada 2 alasan utama, mengapa saya memerlukan Self-Executing Anonymous Functions, atau lebih baik mengatakan " Ekspresi Fungsi yang Segera Diminta (IIFE) ":

  1. Manajemen namespace yang lebih baik (Menghindari Polusi Namespace -> Modul JS)
  2. Penutupan (Mensimulasikan Anggota Kelas Privat, sebagaimana diketahui dari OOP)

Yang pertama telah dijelaskan dengan sangat baik. Untuk yang kedua, pelajari contoh berikut:

var MyClosureObject = (function (){
  var MyName = 'Michael Jackson RIP';
  return {
    getMyName: function () { return MyName;},
    setMyName: function (name) { MyName = name}
  }
}());

Perhatian 1: Kami tidak menetapkan fungsi untuk MyClosureObject, lebih jauh lagi hasil dari memanggil fungsi itu . Waspadai ()baris terakhir.

Perhatian 2: Apa yang harus Anda ketahui tentang fungsi dalam Javascript adalah bahwa fungsi dalam mendapatkan akses ke parameter dan variabel fungsi, yang didefinisikan di dalamnya.

Mari kita coba beberapa eksperimen:

Saya bisa MyNamemenggunakan getMyNamedan berfungsi:

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

Pendekatan jujur ​​berikut ini tidak akan berhasil:

console.log(MyClosureObject.MyName); 
// undefined

Tetapi saya dapat menetapkan nama lain dan mendapatkan hasil yang diharapkan:

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

Sunting: Pada contoh di atas MyClosureObjectdirancang untuk digunakan tanpa newawalan, oleh karena itu konvensi tidak boleh menggunakan huruf kapital.

Kesepian
sumber
7

Apakah ada parameter dan "Bunch of code" mengembalikan fungsi?

var a = function(x) { return function() { document.write(x); } }(something);

Penutupan. Nilai somethingdigunakan oleh fungsi yang ditugaskan untuk a. somethingdapat memiliki beberapa nilai yang bervariasi (untuk loop) dan setiap kali memiliki fungsi baru.

Stesch
sumber
+1; Saya lebih suka eksplisit var x = something;dalam fungsi luar lebih xsebagai parameter, meskipun: imo itu lebih mudah dibaca dengan cara ini ...
Christoph
@Christoph: Jika nilai "sesuatu" berubah setelah fungsi dibuat, maka itu akan menggunakan nilai baru dan bukan yang pada saat pembuatannya.
stesch
@stesch: dari mana Anda mendapatkannya? Sejauh yang saya tahu, bukan itu masalahnya; satu-satunya cara untuk mendapatkan referensi nyata di JS adalah dengan menggunakan argumen-objek, tetapi bahkan itu tidak berfungsi di semua browser
Christoph
@Christoph: "JavaScript: The Good Parts", Douglas Crockford (O'Reilly)
stesch
@stesch: tidak bekerja dengan cara yang Anda menggambarkannya: nilai baru akan digunakan jika Anda drop variabel xdan tergantung langsung pada lingkup leksikal, yaitu document.write(something)...
Christoph
6

Isolasi ruang lingkup, mungkin. Sehingga variabel di dalam deklarasi fungsi tidak mencemari namespace luar.

Tentu saja, pada setengah implementasi JS di luar sana, mereka tetap akan melakukannya.

kekacauan
sumber
4
Apa implementasi itu?
Matthew Crumley
1
Setiap implementasi tidak ditulis dalam mode ketat dan berisi dan deklarasi var implisit yang menyebabkannya menjadi global.
Erik Reppen
5

Berikut ini adalah contoh kuat tentang bagaimana fungsi anonim pemanggilan diri bisa berguna.

for( var i = 0; i < 10; i++ ) {
  setTimeout(function(){
    console.log(i)
  })
}

Keluaran: 10, 10, 10, 10, 10...

for( var i = 0; i < 10; i++ ) {
  (function(num){
    setTimeout(function(){
      console.log(num)
    })
  })(i)
}

Keluaran: 0, 1, 2, 3, 4...

sg.cc
sumber
dapatkah Anda menjelaskan sedikit lebih banyak tentang apa yang terjadi pada rangkaian kode pertama
radio_head
Sebagai letganti varkasus pertama akan baik-baik saja.
Vitaly Zdanevich
3

Satu perbedaan adalah bahwa variabel yang Anda nyatakan dalam fungsi adalah lokal, sehingga mereka hilang ketika Anda keluar dari fungsi dan tidak bertentangan dengan variabel lain dalam kode lain.

Guffa
sumber
1

Karena fungsi dalam Javascript adalah objek kelas satu, dengan mendefinisikannya seperti itu, ia secara efektif mendefinisikan "kelas" seperti C ++ atau C #.

Fungsi itu dapat mendefinisikan variabel lokal, dan memiliki fungsi di dalamnya. Fungsi internal (metode instance efektif) akan memiliki akses ke variabel lokal (variabel instance efektif), tetapi mereka akan diisolasi dari sisa skrip.

James Curran
sumber
1

Fungsi yang dipanggil sendiri dalam javascript:

Ekspresi memohon sendiri dipanggil (dimulai) secara otomatis, tanpa dipanggil. Ekspresi memohon sendiri dipanggil segera setelah dibuat. Ini pada dasarnya digunakan untuk menghindari konflik penamaan serta untuk mencapai enkapsulasi. Variabel atau objek yang dideklarasikan tidak dapat diakses di luar fungsi ini. Untuk menghindari masalah minimisasi (nama file.min) selalu gunakan fungsi yang dieksekusi sendiri.

Kishor Vitekar
sumber
1

Fungsi self executing digunakan untuk mengelola ruang lingkup Variabel.

Lingkup variabel adalah wilayah program Anda di mana ia didefinisikan.

Variabel global memiliki cakupan global; itu didefinisikan di mana-mana dalam kode JavaScript Anda dan dapat diakses dari mana saja di dalam skrip, bahkan dalam fungsi Anda. Di sisi lain, variabel yang dideklarasikan dalam suatu fungsi didefinisikan hanya di dalam tubuh fungsi. Mereka adalah variabel lokal, memiliki cakupan lokal dan hanya dapat diakses dalam fungsi itu. Parameter fungsi juga dihitung sebagai variabel lokal dan hanya didefinisikan dalam tubuh fungsi.

Seperti yang ditunjukkan di bawah ini, Anda dapat mengakses variabel global di dalam fungsi Anda dan juga perhatikan bahwa di dalam tubuh suatu fungsi, variabel lokal diutamakan daripada variabel global dengan nama yang sama.

var globalvar = "globalvar"; // this var can be accessed anywhere within the script

function scope() {
    alert(globalvar);
    localvar = "localvar" //can only be accessed within the function scope
}

scope(); 

Jadi pada dasarnya fungsi mengeksekusi diri memungkinkan kode untuk ditulis tanpa memperhatikan bagaimana variabel dinamai dalam blok kode javascript lainnya.

Adeojo Emmanuel IMM
sumber
1
(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

Sebenarnya, fungsi di atas akan diperlakukan sebagai ekspresi fungsi tanpa nama.

Tujuan utama membungkus suatu fungsi dengan kurung tutup dan terbuka adalah untuk menghindari mencemari ruang global.

Variabel dan fungsi di dalam ekspresi fungsi menjadi pribadi (yaitu) mereka tidak akan tersedia di luar fungsi.

Madhankumar
sumber
1

Jawaban singkatnya adalah: untuk mencegah polusi pada ruang lingkup Global (atau lebih tinggi).

IIFE (Ekspresi Fungsi yang Segera Diminta) adalah praktik terbaik untuk menulis skrip sebagai plug-in, add-on, skrip pengguna, atau skrip apa pun yang diharapkan bekerja dengan skrip orang lain . Ini memastikan bahwa variabel apa pun yang Anda tetapkan tidak memberikan efek yang tidak diinginkan pada skrip lain.

Ini adalah cara lain untuk menulis ekspresi IIFE. Saya pribadi lebih suka metode berikut ini:

void function() {
  console.log('boo!');
  // expected output: "boo!"
}();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

Dari contoh di atas, sangat jelas bahwa IIFE juga dapat memengaruhi efisiensi dan kinerja, karena fungsi yang diharapkan dijalankan hanya sekali akan dieksekusi sekali dan kemudian dibuang ke dalam kehampaan untuk selamanya . Ini berarti bahwa deklarasi fungsi atau metode tidak tetap dalam memori.

Donovan P
sumber
Bagus, saya belum pernah melihat penggunaan itu voidsebelumnya. Saya suka itu.
Ej.
1

Pertama, Anda harus mengunjungi MDN IIFE , Sekarang beberapa poin tentang ini

  • ini adalah Ekspresi Fungsi Segera Diminta . Jadi ketika file javascript Anda dipanggil dari HTML, fungsi ini dipanggil segera.
  • Ini mencegah mengakses variabel dalam idiom IIFE serta mencemari ruang lingkup global.
JustIn
sumber
0

Sepertinya pertanyaan ini sudah dijawab semua sudah siap, tetapi saya tetap akan mengirim masukan saya.

Saya tahu kapan saya ingin menggunakan fungsi self-executing.

var myObject = {
    childObject: new function(){
        // bunch of code
    },
    objVar1: <value>,
    objVar2: <value>
}

Fungsi ini memungkinkan saya untuk menggunakan beberapa kode tambahan untuk mendefinisikan atribut childObjects dan properti untuk kode bersih, seperti mengatur variabel yang biasa digunakan atau menjalankan persamaan matematika; Oh! atau pengecekan error. sebagai lawan menjadi terbatas pada sintaks instantiasi objek bersarang ...

object: {
    childObject: {
        childObject: {<value>, <value>, <value>}
    }, 
    objVar1: <value>,
    objVar2: <value>
}

Pengodean secara umum memiliki banyak cara yang tidak jelas dalam melakukan banyak hal yang sama, membuat Anda bertanya-tanya, "Kenapa repot-repot?" Tetapi situasi baru terus bermunculan di mana Anda tidak bisa lagi mengandalkan prinsip dasar / inti saja.

Garrett
sumber
0

Dengan pertanyaan sederhana Anda: "Dalam javascript, kapan Anda ingin menggunakan ini: ..."

Saya suka jawaban @ken_browning dan @ sean_holding, tetapi berikut ini kasus penggunaan yang tidak saya lihat disebutkan:

let red_tree = new Node(10);

(async function () {
    for (let i = 0; i < 1000; i++) {
        await red_tree.insert(i);
    }
})();

console.log('----->red_tree.printInOrder():', red_tree.printInOrder());

di mana Node.insert adalah beberapa tindakan asinkron.

Saya tidak bisa hanya menelepon menunggu tanpa kata kunci async pada deklarasi fungsi saya, dan saya tidak perlu fungsi bernama untuk digunakan nanti, tetapi perlu menunggu panggilan masukkan itu atau saya memerlukan beberapa fitur kaya lainnya (siapa tahu?) .

zentechinc
sumber
-3

IIRC memungkinkan Anda untuk membuat properti dan metode pribadi.

Ólafur Waage
sumber