Mengapa penutupan penting untuk JavaScript?

16

Ekspresi lambda C # juga memiliki penutup tetapi jarang dibahas oleh komunitas atau buku C #. Saya melihat jauh lebih banyak orang JavaScript dan buku berbicara tentang penutupannya daripada di dunia C #. Mengapa demikian?

TomCaps
sumber
3
Karena JavaScript diperlakukan sebagai bahasa fungsional kelas satu dan C # adalah bahasa OOP klasik. Paradigma yang berbeda, gaya pemrograman yang berbeda.
Raynos
1
Memiliki fungsi kelas satu memang menjadikan bahasa tersebut sebagai bahasa fungsional. PHP (sejak 5.3), python atau D memiliki fungsi kelas satu. Apakah Anda akan mengatakan bahwa mereka adalah bahasa fungsional? Tentu saja tidak, dan javascript juga.
deadalnix
1
@deadalnix JavaScript adalah bahasa multi-paradigma. Ini terutama mendukung paradigma OO prosedural, fungsional dan prototipikal. Ini sama sekali bukan bahasa fungsional murni , tetapi Anda dapat dengan mudah menulis javascript dalam paradigma fungsional tanpa membengkokkan bahasa. Saya akan mengatakan hal yang sama dari C # dan python.
Raynos
3
@deadalnix, bahasa yang memungkinkan Anda mendefinisikan Y-combinator adalah bahasa fungsional. Menurut definisi.
SK-logic
1
@deadalnix: Saya kira apa yang terjadi adalah pertanyaan pendekatan apa yang dipromosikan oleh bahasa. Ada banyak kerangka kerja dan platform JavaScript (terutama node.js dan DOM (model acara)) yang sangat bergantung pada fungsi urutan pertama. PHP memang memiliki fitur yang memungkinkan untuk gaya pemrograman yang sama, tetapi jika Anda melihat pada API standar atau banyak kerangka kerja, maka Anda melihat itu tidak benar-benar inti dari bahasa tersebut.
back2dos

Jawaban:

5

Karena javascript tidak memiliki fitur seperti namespace, dan Anda dapat mengacaukan dengan mudah dengan semua jenis objek global.

Jadi, penting untuk dapat mengisolasi beberapa kode di lingkungan eksekusi sendiri. Penutupan sempurna untuk itu.

Penggunaan penutupan ini tidak masuk akal dalam bahasa seperti C # di mana Anda memiliki ruang nama, kelas, dan sebagainya untuk mengisolasi kode dan tidak menempatkan semuanya dalam lingkup global.

Praktik yang sangat umum untuk kode javascript menulisnya seperti ini:

(function(){
    // Some code
})();

Seperti yang Anda lihat, ini adalah deklarasi fungsi anonim, diikuti segera dengan pelaksanaannya. Dengan demikian, semua yang didefinisikan dalam fungsi tidak mungkin diakses dari luar, dan Anda tidak akan mengacaukan ruang lingkup global. Konteks eksekusi fungsi ini akan tetap hidup selama beberapa kode menggunakannya, seperti fungsi bersarang yang didefinisikan dalam konteks ini, yang dapat Anda lewati sebagai panggilan balik atau apa pun.

Javascript adalah bahasa yang sangat berbeda dari C #. Itu bukan berorientasi objek, itu berorientasi prototipe. Ini mengarah pada praktik yang sangat berbeda pada akhirnya.

Bagaimanapun, penutupannya bagus, jadi gunakanlah, bahkan dalam C #!

EDIT: Setelah beberapa diskusi tentang obrolan stackoverflow, saya pikir jawaban ini harus diawali.

Fungsi dalam kode sampel bukan merupakan penutupan. Namun, fungsi ini dapat mendefinisikan variabel lokal dan fungsi bersarang. Semua fungsi bersarang yang menggunakan variabel lokal ini adalah penutupan.

Ini berguna untuk berbagi beberapa data di seluruh rangkaian fungsi tanpa mengacaukan lingkup global. Ini adalah penggunaan penutupan yang paling umum dalam javascript.

Penutupan jauh lebih kuat daripada hanya berbagi beberapa data seperti ini, tapi mari kita bersikap realistis, sebagian besar programmer tidak tahu apa-apa tentang pemrograman fungsional. Dalam C # Anda akan menggunakan kelas atau namespace untuk jenis penggunaan ini, tetapi JS tidak menyediakan fungsi ini.

Anda dapat melakukan jauh lebih banyak dengan penutupan daripada hanya melindungi ruang lingkup global, tetapi ini adalah apa yang akan Anda lihat dalam kode sumber JS.

deadalnix
sumber
9
Itu bukan penutupan. Anda mendeskripsikan keuntungan menggunakan fungsi untuk membuat cakupan lokal.
Raynos
2
Penutupan hanya penutupan jika ditutup atas variabel bebas. Juga terima kasih telah memberi tahu saya bahwa saya tidak tahu cara kerja JavaScript :)
Raynos
2
daripada memilih untuk melemahkan saya dengan memanggil saya seorang pemula jangan ragu untuk mengajukan argumen yang sebenarnya di ruang Chat JavaScript SO . Diskusi ini sebenarnya bukan di sini, tapi saya akan dengan senang hati membahas kesalahpahaman Anda dalam obrolan SO.
Raynos
1
Diturunkan. JavaScript banyak berorientasi objek. Hanya saja tidak berbasis kelas tetapi fungsi seperti itu mudah dikarang. Ini memiliki fungsi kelas satu, mengambil keuntungan dari penutupan untuk membuatnya cocok alami untuk paradigma yang sangat didorong oleh peristiwa, dan sumber utama inspirasi menurut penulisnya, Brendan Eich, adalah Skema. Saya tidak begitu yakin apa yang Anda pikirkan sebagai bahasa fungsional, tetapi bagian yang lucu adalah bahwa Anda tampaknya berpikir warisan berbasis kelas entah bagaimana kritis daripada tidak lagi sepenuhnya diperlukan ketika Anda dapat melewati fungsi dan menerapkannya dalam konteks baru.
Erik Reppen
2
-1 juga. Ini tidak menjelaskan penutupan, itu menjelaskan ruang lingkup.
Izkata
12

Mungkin karena implementasi populer dari orientasi objek JavaScript bergantung pada penutupan. Mari kita lihat contoh sederhana:

function counter() {
   var value = 0;
   this.getValue = function() { return value; }
   this.increase = function() { value++; }
}

var myCounter = new counter();
console.log(myCounter.getValue());
myCounter.increase();
console.log(myCounter.getValue());

Metode getValuedan increasesebenarnya penutupan, merangkum variabel value.

pengguna281377
sumber
3
-1 "tergantung pada penutupan" Itu sangat subjektif. Itu tidak.
Raynos
Raynos: peduli untuk menunjukkan kepada kita bagaimana membuat dan menggunakan anggota pribadi tanpa penutupan?
user281377
1
@ammoQ tidak ada yang namanya pribadi dalam JavaScript. Apa yang Anda maksudkan adalah "karena emulasi OO klasik JavaScript bergantung pada penutupan". JavaScript OO adalah prototipe yang merupakan paradigma yang berbeda. Ini adalah jawaban yang baik untuk pertanyaan, "Kami menggunakan penutupan dalam JavaScript karena diperlukan untuk meniru OO klasik"
Raynos
1
@keppla yang saya maksudkan "OO tergantung pada penutupan" adalah subjektif. Anda tidak perlu penutupan untuk OO sama sekali.
Raynos
2
Anda mengekspos saya sebagai pelacur rep saya ...
user281377
4

Karena banyak perpustakaan yang membuat JavaScript 'tertahankan' menggunakannya.

Lihatlah JQuery , Prototype atau Mootools , hanya untuk tiga nama populer. Masing-masing perpustakaan menyediakan eachmetode untuk koleksi mereka sebagai cara iterasi yang lebih disukai, yang menggunakan fungsi iterator. Fungsi itu, ketika mengakses nilai dalam lingkup luar, akan menjadi penutup:

[1,2,3].each(function(item) {
   console.log(item);
});

Dan itu tidak berhenti di situ: Callback di Ajax, penanganan event di Ext.js, dll semua mengambil fungsi, dan jika Anda tidak ingin menggembungkan kode Anda dengan 100eds fungsi yang dipanggil tepat sekali, penutupan adalah cara untuk pergi.

keppla
sumber
1
Mengapa ini bukan penutupan? console.logdidefinisikan dalam lingkup luar, jadi consoleadalah 'variabel bebas'. Dan, mengapa, sebenarnya, for-loop, yang tidak ada bedanya, praktik yang buruk?
keppla
@ Raynos: definisi saya tentang penutupan adalah 'blok yang berisi variabel bebas', itu tidak kehilangan status itu, itu variabel bebas kebetulan berada di ruang lingkup teratas. Tetapi, untuk mendukung pendapat saya, pertimbangkan metode ini: pastie.org/2144689 . Mengapa ini harus buruk?
keppla
Saya masih berpikir "menutup" data global dianggap curang. Saya setuju bahwa mengakses data di rantai lingkup baik-baik saja, itu praktik yang baik untuk meminimalkan akses itu.
Raynos
Setuju untuk meminimalkan akses
keppla
Perlu dicatat bahwa dengan iterators array (forEach, map, kurangi, dll) tidak ada alasan bagi mereka untuk ditutup, mereka memiliki semua status yang dilewatkan secara langsung. Saya akan menganggap itu sebagai pola anti bagi mereka sebagai penutupan
Raynos
3

Saya setuju dengan jawaban lain bahwa pengkodean "baik" dengan JavaScript lebih bergantung pada penutupan. Namun, selain itu, mungkin hanya pertanyaan tentang berapa lama fitur tersebut telah ada di setiap bahasa. JavaScript pada dasarnya memiliki penutupan sejak implementasi paling awal. C # di sisi lain hanya memilikinya sejak 3.0, yang dirilis dengan Visual Studio 2008.

Banyak programmer C # yang saya temui masih mengerjakan proyek 2.0. Dan bahkan jika mereka bekerja di 3.0 atau 4.0, mereka sering masih menggunakan 2.0 idiom. Saya suka penutupan; semoga mereka akan menjadi lebih banyak digunakan dalam C # sebagai konsep menyebar di antara pengembang C #.

RasionalGeek
sumber
2

Alasan utamanya adalah karena C # diketik secara statis dan fungsi hanya memiliki akses ke lingkungan tunggal yang telah ditentukan, yang menghambat kegunaan penutupan.

Di JavaScript, di sisi lain, penutupan memungkinkan fungsi berperilaku sebagai metode ketika diakses sebagai properti objek dan menjadi objek kelas satu, mereka juga dapat disuntikkan ke lingkungan yang berbeda yang memungkinkan subrutin beroperasi dalam konteks yang berbeda.

Filip Dupanović
sumber
1
Apa hubungannya pengetikan statis dengan ini? Penutupan bersifat ortogonal.