Javascript ошибка в браузере

Обновлено: 04.07.2024

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

Более подробная информация об инструкциях, рассмотренных в данной главе, содержится в справочнике по JavaScript. Точка с запятой ( ; ) используется для разделения инструкций в коде.

Любое выражение (expression) в JavaScript является также инструкцией (statement). Чтобы получить более подробную информацию о выражениях, прочитайте Выражения и операторы.

Инструкция block

Инструкция block является фундаментальной и используется для группировки других инструкций. Блок ограничивается фигурными скобками:

Блок обычно используется с управляющими инструкциями (например, if , for , while ).

В вышеприведённом примере < x++; >является блоком.

Обратите внимание: в JavaScript отсутствует область видимости блока до ECMAScript2015. Переменные, объявленные внутри блока, имеют область видимости функции (или скрипта), в которой находится данный блок, вследствие чего они сохранят свои значения при выходе за пределы блока. Другими словами, блок не создаёт новую область видимости. "Автономные" (standalone) блоки в JavaScript могут продуцировать полностью отличающийся результат, от результата в языках C или Java. Например:

В вышеприведённом примере инструкция var x внутри блока находится в той же области видимости, что и инструкция var x перед блоком. В C или Java эквивалентный код выведет значение 1.

Начиная с ECMAScript 6, оператор let позволяет объявить переменную в области видимости блока. Чтобы получить более подробную информацию, прочитайте let .

Условные инструкции

Условная инструкция — это набор команд, которые выполняются, если указанное условие является истинным. JavaScript поддерживает две условные инструкции: if. else и switch .

Инструкция if. else

Используйте оператор if для выполнения инструкции, если логическое условия истинно. Используйте опциональный else , для выполнения инструкции, если условие ложно. Оператор if выглядит так:

Здесь condition может быть любым выражением, вычисляемым как истинное (true) или ложное (false). Чтобы получить более подробную информацию о значениях true и false , прочитайте Boolean. Если условие оценивается как true , то выполняется statement_1 , в противном случае - statement_2 . Блоки statement_1 и statement_2 могут быть любыми блоками, включая также вложенные инструкции if .

Также вы можете объединить несколько инструкций, пользуясь else if для получения последовательности проверок условий:

В случае нескольких условий только первое логическое условие, которое вычислится истинным (true), будет выполнено. Используйте блок ( < . >) для группировки нескольких инструкций. Применение блоков является хорошей практикой, особенно когда используются вложенные инструкции if :

Нежелательно использовать простые присваивания в условном выражении, т.к. присваивание может быть спутано с равенством при быстром просмотре кода. Например, не используйте следующий код:

Если вам нужно использовать присваивание в условном выражении, то распространённой практикой является заключение операции присваивания в дополнительные скобки. Например:

Ложные значения

Следующие значения являются ложными:

  • false
  • undefined
  • null
  • 0
  • NaN
  • пустая строка ( "" )

Все остальные значения, включая все объекты, будут восприняты как истина при передаче в условное выражение.

Не путайте примитивные логические значения true и false со значениями true и false объекта Boolean . Например:

В следующем примере функция checkData возвращает true , если число символов в объекте Text равно трём; в противном случае функция отображает окно alert и возвращает false .

Инструкция switch

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

Сначала производится поиск ветви case с меткой label , совпадающей со значением выражения expression . Если совпадение найдено, то соответствующий данной ветви код выполняется до оператора break , который прекращает выполнение switch и передаёт управление дальше. В противном случае управление передаётся необязательной ветви default и выполняется соответствующий ей код. Если ветвь default не найдена, то программа продолжит выполняться со строчки, следующей за инструкцией switch . По соглашению ветвь default является последней ветвью, но следовать этому соглашению необязательно.

Если оператор break отсутствует, то после выполнения кода, который соответствует выбранной ветви, начнётся выполнение кода, который следует за ней.

Инструкции обработки исключений

Инструкция throw используется, чтобы выбросить исключение, а инструкция try. catch , чтобы его обработать.

Типы исключений

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

Инструкция throw

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

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

Примечание: Вы можете выбросить объект как исключение. Вы можете обращаться к свойствам данного объекта в блоке catch .

В следующем примере объект UserException выбрасывается как исключение:

Инструкция try. catch

Инструкция try. catch состоит из блока try , который содержит одну или несколько инструкций, и блок catch , которые содержит инструкции, определяющие порядок действий при выбросе исключения в блоке try . Иными словами, если в блоке try будет выброшено исключение, то управление будет передано в блок catch . Если в блоке try не возникнет исключений, то блок catch будет пропущен. Блок finally будет выполнен после окончания работы блоков try и catch , вне зависимости от того, было ли выброшено исключение.

В следующем примере вызывается функция getMonthName , которая возвращает название месяца по его номеру. Если месяца с указанным номером не существует, то функция выбросит исключение "InvalidMonthNo" , которое будет перехвачено в блоке catch :

Блок catch

Используйте блок catch , чтобы обработать исключения, сгенерированные в блоке try .

JavaScript создаёт идентификатор catchID , которому присваивается перехваченное исключение, при входе в блок catch ; данный идентификатор доступен только в пределах блока catch и уничтожается при выходе из него.

В следующем примере выбрасывается исключение, которое перехватывается в блоке catch :

Блок finally

Блок finally содержит код, который будет выполнен после окончания работы блоков try и catch , но до того, как будет выполнен код, который следует за инструкцией try. catch . Блок finally выполняется вне зависимости от того, было ли выброшено исключение. Блок finally выполняется даже в том случае, если исключение не перехватывается в блоке catch .

В следующем примере открывается файл, затем в блоке try происходит вызов функции writeMyFile , который может выбросить исключение. Если возникает исключение, то оно обрабатывается в блоке catch . В любом случае файл будет закрыт функцией closeMyFile , вызов которой находится в блоке finally .

Если блок finally возвращает значение, то данное значение становится возвращаемым значением всей связки try-catch-finally . Значения, возвращаемые блоками try и catch , будут проигнорированы.

Замена возвращаемых значений блоком finally распространяется в том числе и на исключения, которые выбрасываются или перевыбрасываются в блоке catch :

Вложенные инструкции try. catch

Вы можете вкладывать инструкции try. catch друг в друга. Если внутренняя инструкция try. catch не имеет блока catch , то она должна иметь блок finally, кроме того исключение будет перехвачено во внешнем блоке catch . Для получения большей информации ознакомьтесь с вложенными try-блоками.

Использование объекта Error

В зависимости от типа ошибки вы можете использовать свойства name и message , чтобы получить более подробную информацию. Свойство name содержит название ошибки (например, DOMException или Error ), свойство message — описание ошибки.

Если вы выбрасываете собственные исключения, то чтобы получить преимущество, которое предоставляют эти свойства (например, если ваш блок catch не делает различий между вашими исключениями и системными), используйте конструктор Error . Например:

Объект Promise

Начиная с ECMAScript2015, JavaScript поддерживает объект Promise , который используется для отложенных и асинхронных операций.

Объект Promise может находиться в следующих состояниях:

  • ожидание (pending): начальное состояние, не выполнено и не отклонено.
  • выполнено (fulfilled): операция завершена успешно.
  • отклонено (rejected): операция завершена с ошибкой.
  • заданный (settled): промис выполнен или отклонен, но не находится в состоянии ожидания.


Загрузка изображения при помощи XHR

Типы ошибок

Когда вы делаете что-то не так в коде, есть два основных типа ошибок, с которыми вы столкнётесь:

Ладно, все не так просто — есть и другие отличия, которые вы поймёте, пока будете изучать язык JavaScript глубже. Однако вышеуказанной классификации достаточно на раннем этапе вашей карьеры. Мы рассмотрим оба эти типа в дальнейшем.

Ошибочный пример

Чтобы начать работу, давайте вернёмся к нашей игре с угадыванием чисел — за исключением того, что мы будем изучать версию с некоторыми преднамеренными ошибками. Перейдите в Github и сделайте себе локальную копию number-game-errors.html (см. здесь как это работает).

  1. Чтобы начать работу, откройте локальную копию внутри вашего любимого текстового редактора и вашего браузера.
  2. Попробуйте сыграть в игру — вы заметите, что когда вы нажимаете кнопку «Submit guess», она не работает!

Исправление синтаксических ошибок

Примечание: См. наш TypeError: «x» не является справочной страницей функций для получения дополнительной информации об этой ошибке.

Синтаксические ошибки: второй раунд

Примечание: console.log() это часто используемая функция отладки, которая выводит значение в консоль. Поэтому она будет выводить значение lowOrHi в консоли, как только мы попытаемся установить его в строке 48.


  1. Сохраните и обновите страницу, и вы увидите, что ошибка исчезла.
  2. Теперь, если вы попробуете ввести значение и нажать кнопку "Submit guess", вы увидите . другую ошибку!
  3. На этот раз сообщается об ошибке: "TypeError: lowOrHi is null", в строке 78.
Примечание: Null — это специальное значение, которое означает "ничего" или "не значение". Поэтому lowOrHi был объявлен и инициализирован без значения — у него нет типа или значения. Примечание: Эта ошибка не появилась, как только страница была загружена, потому что эта ошибка произошла внутри функции (внутри checkGuess() < . >block). Об этом вы узнаете более подробно в нашей более поздней статье о функциях, код внутри функций выполняется в отдельной области для кода внешних функций. В этом случае код не был запущен, и ошибка не была брошена до тех пор, пока функция checkGuess() не была запущена строкой 86.

Примечание: Загляните на справочную страницу TypeError: "x" is (not) "y", чтобы узнать больше об этой ошибке.

Синтаксические ошибки: третий раунд

  1. Теперь, если вы снова попробуете сыграть в игру, вы должны добиться большего успеха — игра должна играть абсолютно нормально, пока вы не закончите игру, либо угадав нужное число, либо потеряв жизни.
  2. На данном этапе игра снова слетает, и выводится такая же ошибка, как и в начале — "TypeError: resetButton.addeventListener is not a function"! Однако, теперь она происходит из-за строки 94.
  3. Посмотрев на строку 94, легко видеть, что здесь сделана такая же ошибка. Нам просто нужно изменить addeventListener на addEventListener .

Логическая ошибка

На этом этапе игра должна проходить отлично, однако, поиграв несколько раз, вы, несомненно заметите, что случайное число, которое вы должны угадать, всегда 0 или 1. Определённо не совсем так, как мы хотим, чтобы игра была разыграна!

Безусловно, где-то в игре есть логическая ошибка — игра не возвращает ошибку, она просто работает неправильно.

    Найдём переменную randomNumber , и строку где в первый раз устанавливали случайное число. Пример, в котором мы храним случайное число, которое должны угадать, на строке 44:

И на строке 113, где мы генерируем случайное число, каждый раз после окончания игры:

Работаем через логику

Дальше, мы передаём результат вызова Math.random() через Math.floor() , который округляет число вниз, до ближайшего целого числа. Затем мы добавляем 1 к данному результату:

Округление случайного десятичного числа к меньшему, всегда будет возвращать 0, так что добавление к нему единицы будет возвращать всегда 1. Нам нужно умножить случайное число на 100, прежде чем мы округлим его к меньшему. Следующая строка вернёт нам случайное число между 0 и 99:

поэтому нам нужно добавить 1, чтоб нам возвращалось случайное число между 1 и 100:

А теперь, исправьте обе строки с ошибками, затем сохраните и обновите, игра должна работать так, как мы и планировали!

Другие распространённые ошибки

Существуют и другие распространённые ошибки, которые вы обнаружите в своём коде. В этом разделе показано большинство из них.

SyntaxError: отсутствует ; перед постановкой

Эта ошибка обычно означает что вы упустили точку с запятой в конце одной из ваших строк кода, но иногда ошибка может быть более загадочной. Например, если мы изменим эту строку внутри функции checkGuess() :

Это вызовет данную ошибку, потому что браузер подумает, что вы пытались сделать что-то другое. Вы должны быть уверены, что вы не перепутали оператор присваивания ( = ), который присваивает значение переменной — с оператором сравнения ( === ), который строго сравнивает операнды, и возвращает true / false .

Примечание: Загляните на справочную страницу Синтаксическая ошибка: пропущен символ ; до объявления инструкции для получения дополнительной информации об этой ошибке.

В программе всегда говорится, что вы выиграли, независимо от того, что вы ввели

Причиной этому является все то же перепутывание оператора присваивания ( = ) со строгим сравнением ( === ). Например, если мы изменим внутри checkGuess() эту строку кода:

мы всегда будем получать true , заставляя программу сообщать, что игра была выиграна. Будьте осторожны!

SyntaxError: отсутствует ) после списка аргументов

Эта ошибка проста — обычно она означает, что вы пропустили закрывающую скобку с конца вызова функции / метода.

Примечание: Загляните на справочную страницу SyntaxError: missing ) after argument list для получения дополнительной информации об этой ошибке.

SyntaxError: missing : after property id

Эта ошибка обычно связана с неправильно сформированным объектом JavaScript, но в этом случае нам удалось получить её, изменив

Это заставило браузер думать, что мы пытаемся передать содержимое функции в функцию в качестве аргумента. Будьте осторожны с этими скобками!

SyntaxError: missing > after function body

Это легко — обычно это означает, что вы пропустили одну из ваших фигурных скобок из функции или условной структуры. Мы получили эту ошибку, удалив одну из закрывающих фигурных скобок возле нижней части функции checkGuess() .

SyntaxError: expected expression, got 'string' or SyntaxError: unterminated string literal

Эти ошибки обычно означает, что вы пропустили открывающую или закрывающую кавычку для строковых значений. В первой ошибки выше, строка будет заменена на неожиданный персонаж (ей) , что браузер нашёл вместо кавычек в начале строки. Вторая ошибка означает , что строка не закончилась кавычки.

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

Примечание : Смотрите наш SyntaxError: Неожиданный токен и SyntaxError: незавершённая строка эталонных страниц для получения более подробной информации об этих ошибках.

Резюме

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

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


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Что же поможет найти ошибки JavaScript? Консоль браузера. Здесь мы вкратце пройдемся по этому инструменту в различных браузерах, в частности это будет Firefox и Chrome. В обоих браузерах консоль есть из коробки.

Начнем с Firefox. Для того, чтобы увидеть ошибку в нашем коде, необходимо открыть консоль браузера. Для этого кликаем в окне браузера правой кнопкой мыши и в контекстном меню выбираем пункт Исследовать элемент.


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


Итак, в открывшейся панели рядом со вкладкой Инспектор есть вкладка Консоль, она то нас и интересует. Переключимся на нее, еще раз обновим страницу и увидим все ошибки JavaScript. В нашем случае это всего одна синтаксическая ошибка, которая произошла в файле scripts.js на первой строке.



Вот теперь ошибок нет и код успешно выполнился. Кроме встроенной консоли для Firefox можно отдельно установить расширение Firebug, которое, по сути, является аналогом. После установки Firebug можно вызвать, как и встроенную консоль, из контекстного меню или использовать для этого горячую клавишу F12. Вот таким образом выглядит Firebug:


Ну и консоль Хрома:


Она также вызывается из контекстного меню или клавишей F12.

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


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Вы ожидаете событие onerror, назначая функцию window.onerror:

window . onerror = function ( msg , url , lineNo , columnNo , error ) <

Когда возникает ошибка, в функцию передаются следующие аргументы:


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Первые четыре аргумента говорят вам, в каком скрипте, строке и столбце произошла ошибка. Последний аргумент, объект Error, возможно, самый ценный. Давайте узнаем, почему.

Объект Error и error.stack

На первый взгляд объект Error не является особенным. Он содержит 3 стандартных свойства: message , fileName и lineNumber. Резервированные значения, которые уже предоставлены вам через window.onerror.

Вот пример свойства стека объекта Error в Chrome 46:

"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript._evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)"

Трудно читать, да? Свойство stack на самом деле является просто неформатированной строкой. Вот как выглядит форматирование:

at Object . InjectedScript . _evaluateOn ( < anonymous > : 875 : 140 ) at Object . InjectedScript . _evaluateAndWrap ( < anonymous > : 808 : 34 )

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

Есть только одна загвоздка: свойство стека нестандартно, а его реализация отличается от браузеров. Например, вот те же трассировки стека из Internet Explorer 11:

К счастью, есть инструменты, которые нормализуют свойства стека, так что они совместимы между браузерами. Например, raven-js использует TraceKit для нормализации строк ошибок. Также есть stacktrace.js и несколько других проектов.

Совместимость с браузером

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

Capture и Report JavaScript ошибки с помощью window.onerror

Вероятно, не удивительно, что Internet Explorer 8, 9 и 10 имеют ограниченную поддержку onerror. Но вы можете быть удивлены тем, что Safari только добавила поддержку объекта ошибки в Safari 10 (выпущена в 2016 году). Кроме того, старые мобильные телефоны, которые все еще используют Android-браузер (теперь замененный на Chrome Mobile), все еще там и не пропускают объект ошибки.

Без объекта ошибки нет свойства трассировки стека. Это означает, что эти браузеры не могут извлекать ценную информацию стека из ошибок, обнаруженных в результате атаки.

Polyfilling window.onerror с помощью try / catch


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Рассмотрим следующий вспомогательный метод invoke, который вызывает функцию на объекте с массивом аргументов:

Читайте также: