Различное поведение для разных синтаксических ошибок в javascript

Я не программист на JavaScript, поэтому это может быть действительно простой вопрос. Проблема в том, что при определенных синтаксических ошибках весь код JS не работает.

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

console.log('a')
consol.log('b')    //intentional typo in "console"
console.log('c')

---- output ----
a
ReferenceError: consol is not defined

Приведенный выше пример звучит хорошо в зависимости от того, как должен работать интерпретируемый язык. Теперь взгляните на следующую ошибку:

console.log('a')
console.log('b'    //intentionally didn't put the right parenthesis 
console.log('c')

---- output ----
SyntaxError: missing ) after argument list

Почему нельзя выполнить первую строку?

N.B. Я использовал https://playcode.io для запуска кода и сделал это в Mozilla Firefox.

Парсер должен перевести весь блок кода, прежде чем он сможет работать. Другими словами, он не анализирует строку за строкой. Первая ошибка не является ошибкой синтаксис, потому что consol.log('b') не является ошибкой синтаксически.

Pointy 10.08.2018 15:44

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

Keith 10.08.2018 15:47

Я не профессионал в этом вопросе, но предполагаю, что в наши дни современные браузеры «интерпретируют» javascript на другой язык (ближе к металлу) перед его выполнением. Если он не может проанализировать сценарий из-за синтаксических ошибок, он не может интерпретировать / проанализировать сценарий во что-то еще.

Phil Cooper 10.08.2018 15:48

@phil вещь "ближе к металлу" (я предполагаю, вы имеете в виду JIT-компиляцию) обычно возникает, если определенный код выполняется чаще, но да, движок превращает код в AST перед его запуском ..

Jonas Wilms 10.08.2018 15:53

Потрясающе, спасибо за комментарии. Абсолютно понял сейчас.

Titan 10.08.2018 15:56

Единственный вид кода, в котором может может выполняться по одной «строке» за раз, - это машинный код. Любой другой код, в том числе ассемблер, должен быть заранее обработан кусками и интерпретирован. Как только вы поймете, что одно различие между разными языками заключается в том, насколько большие фрагменты и сколько раз они обрабатываются. Как это часто бывает, движок это JavaScript считывает весь файл сначала в блоке «синтаксиса», а затем снова в блоке «времени выполнения». (И, вероятно, еще много кусков, но они не очевидны.)

Odalrick 10.08.2018 15:57

@Odalrick AFAIK спецификация ES (которой следуют все движки (более или менее)) определяет ранние ошибки, которые возникают до выполнения кода.

Jonas Wilms 10.08.2018 15:58

@JonasWilms Разные JS-движки могут работать по-разному, но из того, что я могу понять, Chromes V8 изначально является собственным кодом, только CrankShaft (оптимизатор) запускает код, который выполняется чаще.

Keith 10.08.2018 16:00

@JonasWilms Да, почти все движки JavaScript работают одинаково. Я думал в общем: если вы введете эти строки в REPL, первая строка будет выполняться даже с синтаксическими ошибками во второй строке. Точно так же, если это были два разных тега сценария на странице html, или разные ячейки в runkit, или ...

Odalrick 10.08.2018 16:10
3
9
117
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Неужели компилятор не считает, что 3-я строка по-прежнему является аргументом строки выше, поскольку вы неправильно закрыли круглые скобки?

Например,

console.log('a')
console.log('b',
console.log('c'))

будет действительным кодом.

Ответ принят как подходящий

consol - это не ошибка синтаксис, это ошибка время выполнения.

Синтаксис - это то, что определяет язык, что заставляет движок Javascript понимать, что вы от него хотите. console.log('b' console.log('c') - это неверный синтаксис, поскольку механизм Javascript не может сказать, забыли ли вы какой-то оператор между 'b' и console, или это отдельные операторы или что вы хотите.

Однако consol.log() - совершенно допустимая команда, предполагая некоторый объект с именем consol существует во время выполнения, что может или не может иметь место в тот момент времени, когда эта строка должна быть выполнена. Вы узнаете только тогда.

Javascript всегда анализирует и компилирует весь код, который вы даете ему для создания работающей программы. Здесь возникает синтаксические ошибки. Только тогда, когда синтаксис верен для всего кода, он выполнит этот код, который затем может или не может создать ошибки времени выполнения.

Since JS is interpreted I thought it should execute each line independently

«Интерпретируемый» тут ни при чем. Возьми это:

while (foo) {
    bar();
}

Очевидно, здесь невозможно выполнить каждую строку независимо, поскольку это составная конструкция. Или это:

foo();

function foo() {}

Этот function должен быть проанализирован и поднятый перед выполнением foo(). Нет, код всегда разбирается сверху вниз до времени выполнения.

В первом примере вы могли бы определить функцию consol.log(). Вы этого не сделали, но его все еще можно проанализировать как вызов функции.

Во втором - браузер не может его разобрать. Прилагаемый ( синтаксически неверен.

Короче говоря, важно то, где именно в парсере обнаружена ошибка.

enter image description here

Другие вопросы по теме