JavaScript интерпретируется как дизайн?

73

Я осторожно задаю этот вопрос, потому что он может показаться слишком разборчивым. Я только что открыл JavaScript: Полное руководство, и в нем говорится о первой странице главы 1

«JavaScript - это высокоуровневый, динамический, нетипизированный интерпретируемый язык программирования»

Поэтому я должен считать, что интерпретируемая часть является требованием в спецификации языка, или вводить в заблуждение утверждение о том, что язык является интерпретируемым языком программирования, учитывая разницу между языком и множеством его реализаций?

По-видимому, для JavaScript нет статических компиляторов - https://stackoverflow.com/questions/1118138/is-there-a-native-machine-code-compiler-for-javascript, так что, возможно, это просто отражение этого.

Мэтт Эш
источник
Некоторое время существовал jscript.net, похожий на AS3 / «потерянный» ES4. Это был скомпилирован байт-код в CIL.
Привет
13
V8 явно заявляет, что он не интерпретатор, а компилятор.
pimvdb
@ GGG JScript.Net все еще жив и ... болен. Но все еще жив. msdn.microsoft.com/en-us/library/72bd815a.aspx
Jetti
1
FWIW, «нетипизированный» бит тоже не совсем верен
Роб Агар
Firefox только что выпустил первый браузерный JIT-компилятор в том году, когда на этот вопрос отвечали в FF 3.5, поэтому он, вероятно, не был широко известен в то время. Я полагаю, что современные JIT действительно много компилируют (или, по крайней мере, готовятся к компиляции) при первом проходе документа JS, чтобы выполнять такие вещи, как методы идентификации и кэширования, которые изолированы для данной области.
Эрик Реппен

Ответы:

50

Поэтому я должен считать, что интерпретируемая часть является требованием в спецификации языка, или вводить в заблуждение утверждение о том, что язык является интерпретируемым языком программирования, учитывая разницу между языком и множеством его реализаций?

Специалисты по языку EcmaScript часто используют термин «интерпретатор ES» для обозначения реализации EcmaScript, но в спецификации этот термин не используется. Обзор языка , в частности , описывает язык переводчика-агностик условиях:

ECMAScript основан на объектах: базовый язык и средства хоста предоставляются объектами, а программа ECMAScript представляет собой кластер взаимодействующих объектов.

Таким образом, EcmaScript предполагает «хост-среду», которая определяется как поставщик определений объектов, включая все те, которые разрешают ввод-вывод или любые другие ссылки на внешний мир, но не требуют интерпретатора.

Семантика операторов и выражений в языке определяется в терминах спецификации завершения, которые тривиально реализуются в интерпретаторе, но в спецификации это не требуется.

8.9 Тип спецификации завершения

Тип Завершение используется для объяснения поведения операторов ( break, continue, returnи throw) , которые выполняют нелокальные передачу управления. Значения типа Завершение - это тройки формы ( тип , значение , цель ), где типом является одно из следующих: обычное , прерывание , продолжение , возврат или выброс , значение - любое значение языка ECMAScript или пустое , а цель - любой идентификатор ECMAScript или пустой .

Термин «внезапное завершение» относится к любому завершению с типом, отличным от нормального .

Нелокальные передачи управления могут быть преобразованы в массивы инструкций с переходами, позволяющими компилировать собственный или байт-код.

«Механизм EcmaScript» может быть лучшим способом выразить ту же идею.


Там нет статических компиляторов для JavaScript, по-видимому

Это неправда. «Интерпретатор» V8 внутренне компилируется в собственный код, Rhino дополнительно компилируется внутри байт-кода Java, а различные интерпретаторы Mozilla ({Trace, Spider, Jager} Monkey) используют JIT-компилятор.

V8 :

V8 повышает производительность, компилируя JavaScript в машинный код перед его выполнением, вместо выполнения байт-кода или его интерпретации.

Rhino :

public final void setOptimizationLevel(int optimizationLevel)

Установите текущий уровень оптимизации. Ожидается, что уровень оптимизации будет целым числом от -1 до 9. Любые отрицательные значения будут интерпретироваться как -1, а любые значения, превышающие 9, будут интерпретироваться как 9. Уровень оптимизации -1 означает, что режим интерпретации всегда будет используемый. Уровни от 0 до 9 указывают, что файлы классов могут быть сгенерированы. Более высокие уровни оптимизации компенсируют производительность во время компиляции для производительности во время выполнения. Уровень оптимизатора не может быть установлен больше -1, если пакет оптимизатора не существует во время выполнения.

TraceMonkey :

TraceMonkey добавляет компиляцию нативного кода в движок Mozilla JavaScript® (известный как «SpiderMonkey»). Он основан на методике, разработанной в Калифорнийском университете в Ирвине, называемой «трассировка деревьев», и основывается на коде и идеях, которыми поделились с проектом Tamarin Tracing. Конечным результатом является значительное увеличение скорости как в браузере Chrome, так и в контенте веб-страниц.

Майк Самуэль
источник
1
Спасибо за этот ответ, на самом деле он отвечает на вопрос. Я полагаю, что последний комментарий о том, что нет статической компиляции, вызвал слух о том, какие реализации фактически компилируют код, а какие нет. Все, что меня интересовало, - это правильность утверждения «JavaScript - интерпретируемый язык», который, учитывая цитаты реализации и отсутствие определения в спецификации, представляется ложным. Не обнадеживает второй абзац «Полного руководства», но, думаю, я буду его придерживаться.
Мэтт Эш
@ me232, заявление было по существу верным до 2008 года. Rhino предшествовал этому, но не был главным интерпретатором, и поэтому немногие могли бы ошибиться в «Полном руководстве» во время его игнорирования. Я не читал книгу, поэтому не могу комментировать, насколько репрезентативно это предложение по своему качеству.
Майк Самуэль,
Каково определение «статического компилятора». Я думал, что это определение означает, что компиляция происходит только один раз, и вы получаете статический (то есть неизменный) набор битов, который затем выполняете. AFAIK это не то, как работает любой движок JavaScript. Вот почему у них есть de-optimizationшаги. Другими словами, JavaScript компилируется этими движками, но статически не компилируется.
мужчина,
@ gman, генератор байт-кода Rhino работает именно так.
Майк Самуэль,
AFAIK это не тот случай. Rhino может включать другие файлы JavaScript, которые должны быть скомпилированы во время выполнения. Это не статическое осложнение.
мужчина
20

Виртуальная машина JavaScript V8, используемая в Chrome, не содержит интерпретатора. Вместо этого он состоит из двух компиляторов и компилирует код на лету. Один из компиляторов работает быстро, но генерирует неэффективный код, другой - оптимизирующий компилятор.

Я могу понять, почему некоторые люди считают это «мошенничеством», поскольку V8 принимает исходный код в качестве входных данных при каждом запуске кода, и пользователь должен установить V8. Но рассмотрим компилятор, который испускает исполняемый файл, который включает полный интерпретатор и байт-код. Тогда у вас будет отдельная программа. Это просто не было бы очень эффективно.

Йорген Фог
источник
19

Появление JIT-компиляторов для языков сценариев размыло грань между компиляцией и интерпретацией до такой степени, что вопрос не так уж много значит. Является ли это только интерпретацией, когда движок читает строку кода и немедленно выполняет ее? (Сценарии оболочки все еще обычно реализуются таким образом.) Является ли это интерпретацией, когда движок берет весь файл, немедленно компилирует его в некоторый байтовый код, а затем интерпретирует байтовый код? (Механизм Mozilla первого этапа работает таким же образом, как и CPython.) Является ли это интерпретацией, когда механизм анализирует функцию за раз и JIT-компилирует ее в собственный код? Как насчет тех движков, которые компилируют весь файл в байтовый код, а затем JIT по одной функции за раз? (Большинство скриптовых движков в наши дни работают так,

Есть много оттенков между компиляцией и интерпретацией.

Я думаю, что наиболее полезным определением для интерпретации является «подача исходного кода программы во время выполнения, без отдельного опережающего шага». По этому определению все движки JavaScript являются интерпретаторами. Но это, конечно, не единственно возможное определение интерпретации.

Но предназначен ли JavaScript для интерпретации? В некотором смысле, да: он имеет evalфункцию, а также Functionконструктор, который вы можете дать программный код в виде строки, которая будет выполняться. Способность динамически создавать программный код во время выполнения требует, чтобы механизм был способен интерпретировать исходный код. Но это не значит, что вы не можете сделать все остальное раньше времени. Даже в скомпилированном языке, таком как C ++ и C #, вы можете взять исходный код, скомпилировать его в памяти для нового машинного кода и затем выполнить его. Для этого есть даже библиотеки: LLVM + Clang на C ++ и проект Roslyn на C #.

Кроме того, механизм доставки для JavaScript является исходным кодом; нет признанной формы байт-кода этого. C # и Java имеют свой официальный байт-код, и все ожидают, что C ++ будет доставлен как машинный код. Но это все еще не неотъемлемый аспект языка, а только сценарий доминирующего использования. Фактически, близкий родственник ActionScript JavaScript во Flash фактически поставляется в виде байтового кода (компилятор Flash предварительно компилирует все сценарии).

Себастьян Редл
источник
4

Не существует полностью согласованного определения «интерпретированный» или «составленный». В классическом различении скомпилированные языки создают отдельный двоичный исполняемый файл, в то время как для интерпретируемых языков требуется развернутая среда выполнения для выполнения кода. Виртуальные машины, байт-код и так далее стирают различия.

Но вот, возможно, полезное определение: интерпретируемый язык - это язык, на котором стандартная языковая среда выполнения может принимать исходный текст в качестве ввода и выполнять его. По этому определению интерпретируются Perl, Python, Ruby, JavaScript и сценарии оболочки и т.п. (даже если они используют промежуточные этапы, такие как байт-код или даже собственный код). Java, C #, C и т. Д. Не являются. И JavaScript по определению интерпретируется, даже если в спецификации не используется точное слово.

JacquesB
источник
Хм, я не люблю ставить Java и C в одну категорию. Возможно, лучшим различием являются языки, которые чаще всего распространяются в виде (A) исходного кода, (B) промежуточного кода или (C) машинного кода. Например, A = javascript, B = Java, C = C.
Джон Хенкель
Называть интерпретируемый или скомпилированный язык неправильно. Например, согласно этому правилу, вы согласитесь, что C ++ - это скомпилированный язык, верно? Тогда как насчет Cling, который выполняет код на C ++ без его компиляции. «и тому подобное интерпретируются (даже если они используют промежуточные шаги, такие как байт-код или даже собственный код)» В соответствии с этим, Java также интерпретируется, интерпретируется его VM.
Абхинав Гауниал