Referensi sendiri penutupan anonim: apakah JavaScript tidak lengkap?

18

Apakah fakta bahwa penutupan fungsi referensi-sendiri anonim begitu menonjol dalam JavaScript menunjukkan bahwa JavaScript adalah spesifikasi yang tidak lengkap? Kami melihat begitu banyak:

(function () { /* do cool stuff */ })();

dan saya kira semuanya adalah masalah selera, tetapi apakah ini tidak terlihat seperti kludge, padahal yang Anda inginkan adalah namespace pribadi? Tidak bisakah JavaScript mengimplementasikan paket dan kelas yang tepat?

Bandingkan dengan ActionScript 3, juga berdasarkan ECMAScript, di mana Anda dapatkan

package com.tomauger {
  import bar;
  class Foo {
     public function Foo(){
       // etc...
     }

     public function show(){
       // show stuff
     }

     public function hide(){
       // hide stuff
     }
     // etc...
  }
}

Kontras dengan konvolusi yang kami lakukan dalam JavaScript (ini, dari dokumentasi pembuat plugin jQuery ):

(function( $ ){

  var methods = {
    init : function( options ) { // THIS },
    show : function( ) { // IS   },
    hide : function( ) { // GOOD },
    update : function( content ) { // !!! }
  };

  $.fn.tooltip = function( method ) {

    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

Saya menghargai bahwa pertanyaan ini dapat dengan mudah berubah menjadi kata-kata kasar tentang preferensi dan gaya pemrograman, tapi saya sebenarnya sangat ingin mendengar bagaimana perasaan Anda para programmer berpengalaman tentang hal ini dan apakah itu terasa alami, seperti mempelajari berbagai keanehan dari bahasa baru, atau kludgy , seperti solusi untuk beberapa komponen bahasa pemrograman dasar yang tidak diimplementasikan?

Tom Auger
sumber
22
"Tidak bisakah JavaScript mengimplementasikan ... kelas yang tepat?" Tidak. Sudah memiliki prototipe yang tepat. Prototipe tidak kalah dengan kelas. Mereka berbeda. Orang-orang telah mencoba menambahkan kelas ke JavaScript pada berbagai waktu dan agak gagal.
Rein Henrichs
5
@Rein: Namun entah bagaimana ActionScript berhasil ...
Mason Wheeler
8
@ Tom tidak ada "kelas bawaan". Tidak ada yang namanya kelas dalam bahasa prototipe . Anda terus menyatukan dua paradigma.
Rein Henrichs
1
Saya pribadi menemukan fitur bahasa fungsi anonim lebih fleksibel daripada kelas. Namun saya suka pemrograman fungsional di mana idiom ini umum.
dietbuddha
1
Bagi yang lain, di sini: brianodell.net/?page_id=516 adalah primer yang luar biasa pada JavaScript sebagai bahasa prototipe.
Tom Auger

Jawaban:

9

Saya kira semuanya adalah masalah selera, tetapi apakah ini tidak terlihat seperti kludge, padahal yang Anda inginkan adalah namespace pribadi? Tidak bisakah JavaScript mengimplementasikan paket dan kelas yang tepat?

Sebagian besar komentar menentang mitos bahwa "prototipe adalah kelas orang miskin", jadi saya hanya akan mengulangi bahwa OO berbasis prototipe tidak kalah dengan OO berbasis kelas.

Titik lain "sebuah kludge ketika semua yang Anda inginkan adalah namespace pribadi". Anda mungkin terkejut mengetahui bahwa Skema menggunakan kludge yang sama persis untuk mendefinisikan cakupan. Itu tidak berhenti dari menjadi contoh dasar dari pelingkupan leksikal yang dilakukan dengan baik.

Tentu saja, dalam Skema, 'kludge' tersembunyi di balik makro ....

Javier
sumber
1
Anda tidak memberikan bukti untuk mendukung pernyataan Anda bahwa Skema adalah contoh utama pelingkupan leksikal yang dilakukan dengan baik, atau bahwa ini ada hubungannya dengan bagaimana Skema menggunakan fungsi untuk mendefinisikan ruang lingkup.
DeadMG
Tidak dapat berbicara dengan Skema sebagai contoh, tetapi salah satu contoh pembuat bersama JS Brendan Eich membahas Skema yang berperan dalam desain JS di sini: readwrite.com/2011/07/22/javascript-was-no-accident
Erik Reppen
7

Pertama, beberapa hal:

  1. Cara lain untuk melihat JavaScript adalah 1 juta dan 1 hal yang dapat Anda lakukan dengan fungsi sebagai konstruk. Semuanya ada di sana jika Anda mencarinya. Hanya saja tidak pernah jauh dari suatu fungsi.

  2. Pengaya plug-in jQuery itu mengerikan. Saya tidak tahu mengapa mereka menganjurkan itu. $ extension harus berupa barang-barang yang umum digunakan yang $ sudah memiliki metode yang cukup baik tidak membangun-saya-a-widget lengkap. Ini adalah alat normalisasi DOM-API. Penggunaannya paling baik dimakamkan di dalam objek Anda sendiri. Saya tidak melihat daya tarik untuk menggunakannya sebagai repositori perpustakaan UI lengkap.

Paket di Web Sisi Klien Tidak Berguna

Yang secara pribadi tidak saya sukai tentang paket di web sisi klien adalah bahwa pada dasarnya kita akan berpura-pura melakukan sesuatu yang sebenarnya tidak kita lakukan. Dalam sebuah postingan .NET webforms dan sekumpulan hal-hal mengerikan yang tidak pernah di-pan-out-dari-teman-teman kita di Java, saya lebih suka memikirkan sebongkah HTML dengan sumber daya tertaut seperti apa sebenarnya. dan tidak mencoba menenangkan pengembang aplikasi OS yang tahan terhadap hal baru dengan berpura-pura itu sesuatu yang lain. Di JS di web sisi klien, tidak ada yang "diimpor" kecuali melakukan sesuatu yang buruk dengan Ajax yang beroperasi dalam ketidaktahuan caching peramban, yang ya, banyak yang telah coba lakukan. Yang penting bagi browser adalah bahwa itu dimuat dan ditafsirkan atau tidak. Kami tidak memiliki lebih banyak kode yang tersimpan di klien di suatu tempat yang tersedia untuk digunakan "untuk berjaga-jaga" untuk alasan yang bagus. # 1 adalah bahwa saya baru saja menggambarkan dependensi plug-in dan plug-in browser untuk aplikasi web karena sebuah fenomena belum berjalan dengan baik. Kami ingin web sekarang. Tidak setelah Adobe atau Sun selesai memperbarui ketiga kalinya minggu ini.

Bahasa Memiliki Apa yang Dibutuhkan untuk Struktur

Objek JS sangat bisa berubah. Kami dapat memiliki pohon percabangan ruang nama pada tingkat apa pun yang kami rasa berguna untuk melakukannya dan itu sangat mudah dilakukan. Tapi ya, untuk apa pun yang dapat digunakan kembali, Anda harus tetap menggunakan root dari perpustakaan mana pun di ruang global. Lagipula semua dependensi terhubung dan dimuat pada saat yang sama, jadi apa gunanya melakukan hal lain? Inti dari menghindari namespace global bukanlah sesuatu yang buruk. Terlalu banyak hal yang buruk karena Anda berisiko tabrakan namespace atau menimpa fitur bahasa inti secara tidak sengaja.

Hanya Karena Populer Tidak Berarti Kita Melakukannya Dengan Benar

Sekarang ketika Anda melihat ini di seluruh aplikasi web sisi klien:

(function(){
//lots of functions defined and fired and statement code here
})()

Masalahnya bukanlah kita kekurangan alat untuk membuat struktur aplikasi, masalahnya adalah orang tidak menilai struktur. Untuk 2-3 halaman sekali pakai situs pembuangan sementara di agensi desain, saya tidak punya masalah dengan itu. Yang menjadi jelek adalah ketika Anda harus membangun sesuatu yang dapat dipelihara dan terbaca serta mudah dimodifikasi.

Tetapi ketika Anda sampai ke tempat di mana saatnya untuk hanya menerapkan semua benda dan pabrik yang dapat digunakan kembali dan mungkin satu atau dua vars sementara baru dapat menyusup ke dalam proses itu, itu adalah kenyamanan.

Tetapi Ada Implementasi JS Dengan Paket / Modul

Perlu diingat bahwa di Node.js, di mana hal-hal seperti itu jauh lebih masuk akal, mereka memiliki modul. JS, dengan asumsi kita dapat menghindari uber-config-hell yang mengganggu bahasa lain, adalah satu-satunya hal dalam persamaan dan setiap file yang dieksekusi adalah ruang lingkupnya sendiri yang terisolasi. Tetapi pada halaman web, menautkan file js sendiri merupakan pernyataan impor. Melakukan lebih banyak impor dengan cepat hanya membuang-buang waktu dan sumber daya karena mendapatkan sumber daya membutuhkan lebih banyak upaya daripada hanya menambahkan tautan ke file karena Anda membutuhkannya mengetahui mereka akan di-cache di browser jika halaman lain membutuhkannya lagi. Jadi sedang mencoba untuk membagi ruang global dengan melakukan apa pun selain membuat pabrik objek adaptor seperti jQuery atau objek yang lebih tradisional yang mencakup sebagian besar tugas dalam domain tertentu sambil menempati satu tempat di global. Sana'http://wiki.ecmascript.org/doku.php?id=harmony:modules

Jadi tidak, tidak ada yang salah dengan auto-invokers digunakan untuk menghindari polusi namespace global ketika ada alasan yang baik untuk menggunakan hal-hal seperti itu (lebih sering daripada tidak ada). Dan kami memiliki properti setara pribadi yang persisten di objek kami (cukup tentukan var di konstruktor dan jangan memaparkannya sebagai properti).

Fakta bahwa kita BISA melakukan hal-hal seperti itu, sungguh luar biasa. Penggunaan yang berat adalah tanda bahwa pengembang JS mungkin masih jatuh tempo, tetapi itu bukan lubang yang menganga dalam bahasa bagi siapa pun yang tidak mencoba memaksakan paradigma ke web sisi klien yang tidak masuk akal di sini.

Erik Reppen
sumber
Kepada Pemilih yang Turun, bisakah Anda menjelaskan mengapa? Ketika seseorang menulis sebanyak itu, saya pikir dia layak mendapat penjelasan!
Songo
+1 jawaban yang bagus, tidak yakin mengapa suara turun sebelum.
tinggalkan
Tulisan yang bagus dan perspektif yang bagus. Saya juga suka "hanya karena itu sebuah piala tidak berarti itu benar.". Saya pikir masalah saya adalah bahwa saya lebih nyaman dengan bahasa yang lebih ketat, yang (IMO) membantu efisiensi pengembangan dalam beberapa cara. JavaScript tampaknya sangat plin-plan dengan tidak banyak built in checks and balances: Anda dapat melakukan apa pun yang Anda inginkan, maka pemandangan di luar sana berantakan idiom dan praktik. Sulit untuk menemukan cara "benar" untuk mendekati struktur kode Anda. Meskipun saya setuju bahwa untuk job-off 1-off cepat, ini bukan masalah besar.
Tom Auger
1
IMO, ada banyak hal yang dapat Anda lakukan dengan banyak tali selain menggantung diri Anda dan Anda belajar menulis kode yang kuat lebih cepat dari gantung diri sesekali yang terjadi lebih jarang ketika Anda mengembangkan kebiasaan yang lebih baik, tetapi saya tidak akan berpura-pura untuk setiap orang atau kandidat yang ideal untuk setiap pekerjaan. Saya curiga semakin banyak Anda mempelajarinya, namun, semakin toleran Anda akan menemukannya. Saya merasa seperti kehilangan setengah otak ketika mencoba melakukan hal-hal dalam bahasa tanpa fungsi kelas satu atau objek yang fleksibel / bisa berubah-ubah seperti JS.
Erik Reppen
4

Hal lain yang Anda lewatkan adalah javscript harus kompatibel. Jika Anda mencoba mengenalkan sintaksis paket, itu bisa merusak web dengan beberapa cara gila. Itu akan buruk! Doug Crockford telah membicarakan hal ini di berbagai titik dan mengapa upaya untuk menambahkannya gagal.

Zachary K
sumber
Itu poin yang bagus. Namun ActionScript berhasil, dengan hanya mengeluarkan versi baru. Saat mendefinisikan tag skrip Anda, Anda selalu dapat menentukan versi JavaScript, jadi "melanggar" situs yang ada seharusnya tidak menjadi masalah.
Tom Auger
1
Dalam praktiknya sebagian besar tag skrip di internet tidak memiliki nomor versi. Sejujurnya saya tidak yakin semua masalah yang satu ini, tapi saya tahu bahwa orang-orang yang memikirkan hal ini telah memutuskan bahwa itu tidak bisa dilakukan.
Zachary K
1
@ Tom: Adobe juga memiliki kendali penuh atas platform Flash. Tidak ada satu entitas yang memiliki kontrol penuh atas semua platform JS di luar sana. Selain itu, hanya menempelkan nomor versi untuk skrip JS di peramban akan berarti Anda tidak mendukung peramban yang lebih lama atau harus menulis dua skrip. Jadi, ini adalah masalah.
Jeremy Heiler
2

Ya, itu adalah kludge.

Banyak orang mengatakan bahwa "prototipe tidak kalah dengan kelas". Saya tidak setuju, tapi itu masalah pilihan. Tapi itu bahkan bukan masalah sebenarnya dengan JavaScript - masalahnya adalah bahwa itu awalnya dirancang sebagai bahasa scripting cepat dan kotor untuk membuat hal-hal seperti tombol animasi. Kembali di pertengahan 90-an tidak ada yang pernah berpikir bahwa JavaScript akan diminta untuk melakukan beberapa hal gila yang sedang dilakukan sekarang.

Mike Baranczak
sumber
6
Saya tidak setuju, JavaScript bahasanya sebenarnya sangat luar biasa. Bahwa itu disatukan dengan DOM yang ditentukan dan tidak kompatibel satu sama lain adalah tempat semua masalah dimulai.
Dean Harding
2
Apa hubungannya ini dengan prototipe?
Erik Reppen
2

Fungsi pemanggilan mandiri anonim lebih mirip dengan modul daripada ke kelas. Sangat menjengkelkan bahwa standar untuk javascript dijalankan di lingkup global. Panitia yang mengerjakan JS.next secara serius mempertimbangkan untuk menambahkan modul, sehingga Anda tidak memasukkan variabel lokal Anda ke dalam lingkup global. Untungnya, fungsi Javascript memiliki semantik yang nyaman sehingga kita dapat menggunakan fungsi anonim sebagai ruang lingkup pribadi dengan relatif mudah.

Saya tidak melihat bagaimana kelas benar-benar masuk ke dalam diskusi sama sekali, kecuali bahwa mereka adalah konstruksi pelingkupan tingkat atas dalam banyak bahasa. Modul / paket / tolong-beri-aku-lingkup-lokal-jadi-aku-jangan-tinggalkan-variabel-saya-dalam-lingkungan-global yang lebih baik akan sangat menyenangkan untuk dimiliki.

Sean McMillan
sumber
1

Anda mungkin ingin melihat ExtJS 3 dan 4 di mana mereka telah berhasil mengimplementasikan ruang nama dengan cukup baik.

- ditambahkan setelah -1

Maksud saya di sini adalah, mungkin untuk menyembunyikan semua 'konvolusi' ini dan masih memiliki kode yang cukup ramah seperti:

Ext.ns('com.tomauger');
Ext.Loader.load('bar.js'); //unfortunately filname needs to be used
MyNameSpace.Foo = {
   //...
}
Mchl
sumber