Ostrożnie zadaję to pytanie, ponieważ może wydawać się zbyt wybredne. Właśnie otworzyłem JavaScript: The Definitive Guide i zawiera on pierwszą stronę rozdziału 1
„JavaScript jest dynamicznym, dynamicznym, bez typowania interpretowanym językiem programowania na wysokim poziomie”
Czy mam zatem przyjąć, że interpretowana część jest wymogiem w specyfikacji języka, czy też mylące jest twierdzenie, że język jest interpretowanym językiem programowania, jeśli chodzi o różnicę między językiem a jego wieloma implementacjami?
Najwyraźniej nie ma statycznych kompilatorów dla JavaScript - https://stackoverflow.com/questions/1118138/is-there-a-native-machine-code-compiler-for-javascript, więc może to tylko odzwierciedlenie tego.
javascript
Matt Esch
źródło
źródło
Odpowiedzi:
Maniacy języka EcmaScript często używają terminu „tłumacz ES” w odniesieniu do implementacji EcmaScript, ale specyfikacja nie używa tego terminu. Przegląd język w szczególności opisuje język w kategoriach tłumacza-agnostyk:
Tak więc EcmaScript zakłada „środowisko hosta”, które jest zdefiniowane jako dostawca definicji obiektów, w tym wszystkie te, które zezwalają na operacje we / wy lub jakiekolwiek inne łącza do świata zewnętrznego, ale nie wymagają interpretera.
Semantyka instrukcji i wyrażeń w języku jest zdefiniowana w kategoriach specyfikacji uzupełniania, które są trywialnie zaimplementowane w interpreterie, ale specyfikacja tego nie wymaga.
Nielokalne przekazywanie kontroli można przekształcić w tablice instrukcji ze skokami pozwalającymi na kompilację kodu natywnego lub bajtowego.
„EcmaScript Engine” może być lepszym sposobem wyrażenia tego samego pomysłu.
To nie jest prawda. „Interpreter” V8 kompiluje wewnętrznie kod macierzysty, Rhino opcjonalnie kompiluje wewnętrznie kod bajtowy Java, a różne interpretery Mozilli ({Trace, Spider, Jager} Monkey) używają kompilatora JIT.
V8 :
Nosorożec :
TraceMonkey :
źródło
de-optimization
kroki. Innymi słowy JavaScript jest kompilowany przez te silniki, ale nie jest kompilowany statycznie.Wirtualna maszyna wirtualna JavaScript V8 używana w Chrome nie zawiera interpretera. Zamiast tego składa się z dwóch kompilatorów i kompiluje kod w locie. Jeden z kompilatorów działa szybko, ale generuje nieefektywny kod, drugi to kompilator optymalizujący.
Rozumiem, dlaczego niektórzy ludzie uważają to „oszukiwanie”, ponieważ V8 pobiera kod źródłowy jako dane wejściowe za każdym razem, gdy kod jest uruchamiany, a użytkownik musi zainstalować V8. Ale rozważ kompilator, który emituje plik wykonywalny, który zawiera kompletny interpreter i kod bajtowy. Wtedy miałbyś samodzielny program. To po prostu nie byłoby bardzo wydajne.
źródło
Pojawienie się kompilatorów JIT dla języków skryptowych zatarło granicę między kompilacją a interpretacją do tego stopnia, że pytanie nie znaczy aż tyle. Czy to tylko interpretacja, gdy silnik odczytuje wiersz kodu i natychmiast go wykonuje? (Skrypty powłoki są zwykle zwykle implementowane w ten sposób.) Czy to interpretacja, gdy silnik pobiera cały plik, natychmiast kompiluje go do jakiegoś kodu bajtowego, a następnie interpretuje kod bajtowy? (Pierwszy etap silnika Mozilli działa w ten sposób, podobnie jak CPython.) Czy to interpretacja, gdy silnik analizuje funkcję na raz i JIT kompiluje ją do kodu natywnego? Co z tymi silnikami, które kompilują cały plik do kodu bajtowego, a następnie JIT w razie potrzeby jedną funkcję na raz? (Obecnie większość silników skryptowych działa w ten sposób,
Istnieje wiele odcieni między kompilacją a interpretacją.
Myślę, że najbardziej użyteczną definicją interpretacji jest „podaje kod źródłowy programu w czasie wykonywania, bez osobnego kroku wyprzedzającego”. Zgodnie z tą definicją wszystkie silniki JavaScript są tłumaczami. Ale z pewnością nie jest to jedyna możliwa definicja interpretacji.
Ale czy JavaScript jest przeznaczony do interpretacji? W pewnym sensie tak: ma zarówno
eval
funkcję, jak iFunction
konstruktor, że możesz podać kod programu jako ciąg znaków, który zostanie wykonany. Zdolność do dynamicznego konstruowania kodu programu w czasie wykonywania wymaga, aby silnik mógł interpretować kod źródłowy. Ale to nie znaczy, że nie da się zrobić wszystkiego z wyprzedzeniem. Nawet w skompilowanym języku, takim jak C ++ i C #, możesz pobrać kod źródłowy, skompilować go w pamięci do nowego kodu maszynowego, a następnie go uruchomić. Istnieją nawet biblioteki: LLVM + Clang w C ++ i projekt Roslyn w C #.Ponadto mechanizmem dostarczania kodu JavaScript jest kod źródłowy; nie ma rozpoznanej formy kodu bajtowego. C # i Java mają swój oficjalny kod bajtowy i wszyscy oczekują, że C ++ będzie dostarczany jako kod maszynowy. Ale to wciąż nie jest nieodłącznym aspektem, jeśli język, tylko dominujący scenariusz użycia. W rzeczywistości bliski krewny ActionScript JavaScript we Flashu jest w rzeczywistości dostarczany jako kod bajtowy (kompilator Flash wstępnie kompiluje wszystkie skrypty).
źródło
Nie ma całkowicie uzgodnionej definicji „interpretowane” a „skompilowane”. W klasycznym rozróżnieniu języki skompilowane tworzą autonomiczny binarny plik wykonywalny, podczas gdy języki interpretowane wymagają wdrożonego środowiska wykonawczego do wykonania kodu. Maszyny wirtualne, kod bajtowy itd. Zacierają rozróżnienie.
Ale oto prawdopodobnie przydatna definicja: język interpretowany to język, w którym standardowy język wykonawczy języka może pobierać tekst kodu źródłowego jako dane wejściowe i go wykonywać. Zgodnie z tą definicją interpretuje się skrypty Perl, Python, Ruby, JavaScript i powłoki itp. (Nawet jeśli używają pośrednich kroków, takich jak kod bajtowy lub nawet kod macierzysty). Java, C #, C itp. Nie są. JavaScript jest z definicji interpretowany, nawet jeśli specyfikacja nie używa dokładnego słowa.
źródło