Apakah JavaScript diinterpretasikan oleh desain?

73

Saya berhati-hati untuk mengajukan pertanyaan ini karena mungkin terlihat terlalu rewel. Saya baru saja membuka JavaScript: Panduan Definitif, dan menyatakan halaman pertama bab 1

"JavaScript adalah bahasa pemrograman tingkat tinggi, dinamis, dan tidak ditafsirkan"

Jadi apakah saya harus menganggap bahwa bagian yang ditafsirkan adalah persyaratan dalam spesifikasi bahasa, atau apakah itu menyesatkan untuk mengatakan bahwa bahasa tersebut adalah bahasa pemrograman yang ditafsirkan ketika menghormati perbedaan antara bahasa dan banyak implementasinya?

Tampaknya tidak ada kompiler statis untuk JavaScript - https://stackoverflow.com/questions/1118138/is-there-a-nnative-machine-code-compiler-for-javascript jadi mungkin itu hanya cerminan dari ini.

Matt Esch
sumber
Ada jscript.net untuk sementara waktu yang mirip dengan AS3 / ES4 "hilang". Itu bytecode-dikompilasi ke CIL.
Hei
13
V8 secara eksplisit mengklaim bukan sebagai juru bahasa, melainkan penyusun.
pimvdb
@GGG JScript.Net masih hidup dan ... sakit-sakitan. Tapi masih hidup. msdn.microsoft.com/en-us/library/72bd815a.aspx
Jetti
1
FWIW, bit "yang tidak diketik" juga tidak sepenuhnya benar
Rob Agar
Firefox baru saja merilis kompiler JIT berbasis browser pertama tahun itu pertanyaan dijawab dalam FF 3.5 sehingga mungkin tidak diketahui secara luas pada saat itu. Saya percaya JIT modern benar-benar melakukan banyak kompilasi (atau setidaknya persiapan untuk kompilasi) pada pass pertama dari dokumen JS untuk melakukan hal-hal seperti mengidentifikasi dan metode cache yang diisolasi untuk lingkup yang diberikan.
Erik Reppen

Jawaban:

50

Jadi apakah saya harus menganggap bahwa bagian yang ditafsirkan adalah persyaratan dalam spesifikasi bahasa, atau apakah itu menyesatkan untuk mengatakan bahwa bahasa tersebut adalah bahasa pemrograman yang ditafsirkan ketika menghormati perbedaan antara bahasa dan banyak implementasinya?

Geeks bahasa EcmaScript sering menggunakan istilah "ES interpreter" untuk merujuk pada implementasi EcmaScript, tetapi spec tidak menggunakan istilah itu. The gambaran bahasa khususnya menggambarkan bahasa dalam hal interpreter-agnostik:

ECMAScript berbasis objek: bahasa dasar dan fasilitas host disediakan oleh objek, dan program ECMAScript adalah sekelompok objek yang berkomunikasi.

Jadi EcmaScript mengasumsikan "lingkungan host" yang didefinisikan sebagai penyedia definisi objek termasuk semua yang memungkinkan I / O atau tautan lain ke dunia luar, tetapi tidak memerlukan juru bahasa.

Semantik pernyataan dan ungkapan dalam bahasa didefinisikan dalam hal spesifikasi penyelesaian yang sepele diimplementasikan dalam juru bahasa, tetapi spesifikasi tidak mengharuskan itu.

8.9 Jenis Spesifikasi Penyelesaian

Jenis Penyelesaian digunakan untuk menjelaskan perilaku pernyataan ( break, continue, returndan throw) yang melakukan transfer nonlokal kontrol. Nilai dari jenis Penyelesaian adalah tiga kali lipat dari bentuk ( tipe , nilai , target ), di mana jenisnya adalah normal , rusak , lanjutkan , kembali , atau lempar , nilainya adalah setiap nilai bahasa ECMASkriptika atau kosong , dan target adalah pengidentifikasi atau skrip ECMAScript kosong .

Istilah "penyelesaian tiba-tiba" mengacu pada penyelesaian apa pun dengan jenis selain dari normal .

Transfer kontrol non-lokal dapat dikonversi ke array instruksi dengan lompatan yang memungkinkan untuk kompilasi kode asli atau byte.

"Mesin EcmaScript" mungkin cara yang lebih baik untuk mengekspresikan ide yang sama.


Rupanya tidak ada kompiler statis untuk JavaScript

Ini tidak benar. V8 "interpreter" mengkompilasi ke kode asli secara internal, Rhino secara opsional mengkompilasi ke bytecode Java secara internal, dan berbagai penerjemah Mozilla ({Trace, Spider, Jager} Monkey) menggunakan kompiler JIT.

V8 :

V8 meningkatkan kinerja dengan mengkompilasi JavaScript ke kode mesin asli sebelum menjalankannya, dibandingkan mengeksekusi bytecode atau menafsirkannya.

Badak :

public final void setOptimizationLevel(int optimizationLevel)

Tetapkan level optimisasi saat ini. Tingkat optimisasi diharapkan menjadi bilangan bulat antara -1 dan 9. Nilai negatif apa pun akan ditafsirkan sebagai -1, dan nilai apa pun yang lebih besar dari 9 akan ditafsirkan sebagai 9. Tingkat optimisasi -1 menunjukkan bahwa mode interpretif akan selalu menjadi bekas. Level 0 hingga 9 menunjukkan bahwa file kelas dapat dihasilkan. Level optimisasi yang lebih tinggi menukar kinerja waktu kompilasi untuk kinerja runtime. Level optimizer tidak dapat ditetapkan lebih besar dari -1 jika paket optimizer tidak ada pada saat run time.

TraceMonkey :

TraceMonkey menambahkan kompilasi kode asli ke mesin JavaScript® Mozilla (dikenal sebagai "SpiderMonkey"). Ini didasarkan pada teknik yang dikembangkan di UC Irvine yang disebut "pohon jejak", dan membangun kode dan ide yang dibagikan dengan proyek Tamarin Tracing. Hasil akhirnya adalah peningkatan kecepatan besar-besaran di browser chrome dan konten halaman Web.

Mike Samuel
sumber
1
Terima kasih atas jawaban ini, sebenarnya menjawab pertanyaan itu. Saya kira komentar terakhir tentang tidak ada kompilasi statis adalah apa yang menyebabkan buzz tentang implementasi mana yang benar-benar mengkompilasi kode dan mana yang tidak. Yang saya tertarik adalah validitas pernyataan "JavaScript adalah bahasa yang ditafsirkan" yang, mengingat kutipan implementasi dan kurangnya definisi oleh spesifikasi, tampaknya salah. Tidak mendukung paragraf kedua dari "Panduan Definitif", tapi saya rasa saya akan tetap menggunakannya.
Matt Esch
@ me232, pernyataan itu secara substansial benar sebelum tahun 2008. Badak pra-tanggal itu tetapi bukan penerjemah utama dan sedikit sekali yang akan menyalahkan "the Definitive Guide" pada saat mengabaikannya. Saya belum membaca buku itu, jadi saya tidak bisa mengomentari seberapa representatif kalimat itu dari kualitas keseluruhannya.
Mike Samuel
Apa definisi "kompiler statis". Saya pikir definisi itu berarti kompilasi hanya terjadi sekali dan Anda mendapatkan ember bit statis (yaitu, tidak berubah) yang kemudian Anda jalankan. AFAIK ini bukan cara kerja mesin JavaScript. Itu sebabnya mereka punya de-optimizationlangkah. Dengan kata lain JavaScript dikompilasi oleh mesin ini tetapi tidak dikompilasi secara statis.
GM
@ gman, generator bytecode Rhino bekerja seperti itu.
Mike Samuel
AFAIK bukan itu masalahnya. Badak dapat menyertakan file JavaScript lain yang harus dikompilasi saat runtime. Itu bukan komplikasi statis .
GM
20

V8 JavaScript VM yang digunakan di Chrome tidak termasuk juru bahasa. Sebaliknya itu terdiri dari dua kompiler dan mengkompilasi kode dengan cepat. Salah satu kompiler berjalan cepat tetapi menghasilkan kode yang tidak efisien, yang lain adalah kompiler yang mengoptimalkan.

Saya bisa mengerti mengapa beberapa orang menganggap ini "curang", karena V8 mengambil kode sumber sebagai input setiap kali kode berjalan dan pengguna harus menginstal V8. Tetapi pertimbangkan kompiler yang memancarkan executable yang meliputi juru bahasa lengkap dan bytecode. Maka Anda akan memiliki program yang berdiri sendiri. Itu tidak akan sangat efisien.

Jørgen Fogh
sumber
19

Munculnya kompiler JIT untuk bahasa skrip telah mengaburkan batas antara kompilasi dan interpretasi ke titik di mana pertanyaannya tidak terlalu berarti. Apakah ini hanya interpretasi ketika mesin membaca sebaris kode dan segera menjalankannya? (Script shell masih biasanya diimplementasikan dengan cara ini.) Apakah ini interpretasi ketika mesin mengambil seluruh file, segera mengkompilasinya ke beberapa kode byte, dan kemudian mengartikan kode byte? (Mesin Mozilla tahap pertama bekerja dengan cara ini, seperti halnya CPython.) Apakah itu interpretasi ketika mesin mem-parsing suatu fungsi pada suatu waktu dan JIT-mengkompilasinya ke kode asli? Bagaimana dengan mesin-mesin yang mengkompilasi seluruh file ke kode byte, lalu JIT satu fungsi sekaligus sesuai kebutuhan? (Sebagian besar mesin skrip hari ini bekerja dengan cara ini,

Ada banyak corak antara kompilasi dan interpretasi.

Saya pikir definisi yang paling berguna untuk interpretasi adalah "diumpankan kode sumber program pada waktu eksekusi, tanpa langkah sebelumnya yang terpisah". Menurut definisi ini, semua mesin JavaScript adalah juru bahasa. Tetapi ini tentu saja bukan satu-satunya definisi interpretasi yang mungkin.

Tetapi apakah JavaScript dirancang untuk interpretasi? Di satu sisi, ya: ia memiliki evalfungsi serta Functionkonstruktor yang dapat Anda berikan kode program sebagai string yang akan dieksekusi. Kemampuan untuk membuat kode program secara dinamis pada saat dijalankan mengharuskan engine mampu menginterpretasikan kode sumber. Tetapi ini tidak berarti bahwa Anda tidak dapat membuat segala sesuatu yang lain sebelumnya. Bahkan dalam bahasa yang dikompilasi seperti C ++ dan C # Anda dapat mengambil kode sumber, kompilasi dalam memori ke kode mesin baru dan kemudian jalankan itu. Bahkan ada perpustakaan untuk itu: LLVM + Dentang di C ++ dan proyek Roslyn di C #.

Juga, mekanisme pengiriman untuk JavaScript adalah kode sumber; tidak ada bentuk kode byte yang dikenali darinya. C # dan Java memiliki kode byte resmi mereka, dan semua orang mengharapkan C ++ dikirimkan sebagai kode mesin. Namun ini masih bukan aspek bawaan jika bahasa, hanya skenario penggunaan dominan. Faktanya, ActionScript relatif dekat JavaScript di Flash sebenarnya dikirim sebagai kode byte (kompiler Flash mengkompilasi semua skrip).

Sebastian Redl
sumber
4

Tidak ada yang sepenuhnya disepakati definisi 'ditafsirkan' versus 'dikompilasi'. Dalam perbedaan klasik, bahasa yang dikompilasi menghasilkan biner yang dapat dieksekusi, sementara bahasa yang ditafsirkan membutuhkan runtime yang digunakan untuk mengeksekusi kode. Mesin virtual, bytecode dan sebagainya mengaburkan perbedaan.

Tapi di sini ada definisi yang mungkin berguna: Bahasa yang ditafsirkan adalah bahasa di mana runtime bahasa standar dapat mengambil teks kode sumber sebagai input dan menjalankannya. Dengan definisi itu Perl, Python, Ruby, JavaScript dan skrip shell dan sejenisnya ditafsirkan (bahkan jika mereka menggunakan langkah-langkah menengah seperti bytecode atau bahkan kode asli). Java, C #, C dll tidak. Dan JavaScript menurut definisi ditafsirkan, bahkan jika spec tidak menggunakan kata yang tepat.

JacquesB
sumber
Hmm, saya tidak suka menempatkan Java dan C dalam kategori yang sama. Mungkin perbedaan yang lebih baik adalah bahasa yang paling umum didistribusikan sebagai (A) kode sumber, (B) kode menengah, atau (C) kode mesin. Misalnya A = javascript, B = Java, C = C.
John Henckel
Memanggil bahasa yang ditafsirkan atau dikompilasi tidak benar. Misalnya di bawah aturan itu, Anda akan setuju bahwa C ++ dikompilasi dalam bahasa kan? Lalu bagaimana dengan Cling, yang mengeksekusi kode c ++ tanpa mengompilasinya. "dan sejenisnya ditafsirkan (bahkan jika mereka menggunakan langkah-langkah menengah seperti bytecode atau bahkan kode asli)" Menurut ini, java ditafsirkan juga, ditafsirkan oleh VM-nya.
Abhinav Gauniyal