Ошибки в JavaScript: исправляем, обрабатываем, чиним
Всем привет! Вдохновленные успехом предыдущей статьи, которая была написана в преддверии запуска курса «Fullstack разработчик JavaScript«, мы решили продолжить серию статей для новичков и всех тех, кто только начинает заниматься программированием на языке JavaScript. Cегодня мы поговорим об ошибках, которые случаются в JS, а также о том, как именно с ними бороться.
Отдебажь за человека одну ошибку, и он будет благодарен тебе один пулл реквест. Научи его дебажить самостоятельно, и он будет благодарен тебе весь проект.
Типичные ошибки начинающих
Итак, начнем с самых примитивных ошибок. Допустим, вы только недавно закончили изучать основы HTML и CSS и теперь активно принялись за программирование на JavaScript. Для примера: вы хотите, чтобы при клике на кнопку у вас открывалось, к примеру, скрытое до этого момента модальное окно. Так же вы хотите, чтобы у вас по нажатию на крестик это окно закрывалось. Интерактивный пример доступен здесь (я выбрал bitbucket из-за того, что его интерфейс мне кажется самым простым, да и не все же на гитхабе сидеть).
В нашем index.html, кроме верстки, мы внутри тэга head вставляем наш script:
В index.html кроме верстки внутри тэга head мы вставляем наш script :
Однако, несмотря на то, что мы все подключили, ничего не заработает и вылетит ошибка:

Что весьма печально, новички часто теряются и не понимают, что делать с красными строчками, словно это приговор какой-то, а не подсказка о том, что не так в вашей программе. Если перевести, то браузер говорит нам, что он не может прочитать свойство addEventListener нулевого значения. Значит, почему-то из DOM модели мы не получили наш элемент. Какой алгоритм действий нужно предпринять?
Во-первых, посмотрите в какой момент у вас вызывается javascript . Браузер читает ваш html-код сверху вниз, как вы читаете, например, книгу. Когда он увидит тэг script , то сразу исполнит его содержимое и продолжит чтение следующих элементов, не особо заботясь о том, что в своем скрипте вы пытаетесь получить элементы DOM, а он их еще не прочитал и, следовательно, не построил модель.
Что делать в таком случае? Просто добавьте атрибут defer внутрь вашего тэга скрипт (или async , но я не буду сейчас вдаваться в подробности их работы, это можно прочитать здесь ). Или можете просто переместить вниз ваш тэг script перед закрывающим body , это тоже сработает.
Во-вторых, проверьте опечатки. Изучите методологию БЭМ — она полезна ещё и тем, что вы хорошо знаете, как пишется ваш элемент — ведь пишите классы по единой логике, и стараетесь пользоваться только правильным английским языком. Или копируете сразу название элемента в JS файл.
Отлично. Теперь, когда вы поправили ошибки, можете насладиться рабочей версией кода по следующему адресу.
Загадочная ошибка
Больше всего новичков вводит в ступор странная ошибка последней строчки кода. Приведем пример:

В консоли выводится что-то непонятное. Если переводить, то буквально это «Неожиданный конец ввода» — и что с этим делать? Кроме того, новичок по привычке смотрит на номер строки. На ней вроде все нормально. И почему тогда консоль на нее указывает?
Все просто. Что бы понимать, как интерпретировать вашу программу, интерпретатору JS нужно знать, где заканчивается тело функции, и где заканчивается тело цикла. В данном варианте кода я абсолютно намеренно забыл последнюю фигурную скобку:
Теперь JavaScript не понимает, где у него конец тела функции, а где конец цикла и не может интерпретировать код.
Что делать в данном случае? В любом современном редакторе кода, если вы поставите курсор перед открывающей скобкой, подсветится его закрывающий вариант (если редактор еще не начал подчеркивать эту ошибку красным цветом). Просмотрите код еще раз внимательно, держа в голове, что в JS не бывает одиноких фигурных скобок. Проблемный вариант можно посмотреть здесь, а исправленный — вот тут.
Дробим код
Чаще всего стоит заниматься написанием кода, тестируя его работу небольшими кусочками. Или как нормальный человек изучить TDD К примеру, вам нужно простую программу, которая принимает данные на вход от пользователя, складывает их в массив и после этого выводит их средние значения:
На первый неискушенный взгляд, в данном коде вполне все нормально. В нем есть основная логика, раздробленная на две функции, каждую из которой можно применять потом отдельно. Однако опытный программист сразу скажет, что это не заработает, ведь из prompt данные к нам приходят в виде строки. Причем JS (таков его толерантно-пофигистичный характер) нам все запустит, но на выходе выдаст настолько невероятную чепуху, что даже будет непросто понять, как мы дошли до жизни такой. Итак, давайте попробуем что-нибудь посчитать в нашем интерактивном примере. Введем допустим число 3 в количество переменных, и 1 2 3 в поле ввода данных:

Что? Чего? Ладно, это JavaScript. Поговорим лучше, как мы могли бы избежать такого странного вывода. Надо было писать на Python, он бы по-человечески предупредил нас об ошибке. Нам надо было после каждого подозрительного момента сделать вывод типа переменных и смотреть, в каком состоянии находится наш массив.
Вариант кода, в котором вероятность неожиданного вывода снижена:
Иными словами, все подозрительные места, в которых что-то могло пойти не так, я вывел в консоль, чтобы убедиться, что все идет так, как я ожидаю. Конечно, данные console.log — детские игрушки и в норме, естественно, нужно изучить любую приличную библиотеку для тестирования. Например эту. Результат этой отладочной программы можно увидеть в инструментах разработчика здесь. Как починить, я думаю, вопросов не будет, но если если интересно, то вот (и да, это можно сделать просто двумя плюсами).

Шаг вперед: осваиваем Chrome Dev Tools
Дебаг с использованием console.log в 2019 — это уже несколько архаичная штука (но мы все равно ее никогда ее не забудем, она уже нам как родная). Каждый разработчик, который мечтает носить гордое звание профессионала, должен освоить богатый инструментарий современных средств разработки.
Попробуем починить проблемные места в нашем коде с помощью Dev Tools. Если нужна документация с примерами, всё можно прочитать вот здесь. А мы попробуем разобрать предыдущий пример с помощью Dev Tools.
Итак, открываем пример. У нас явно запрятался какой-то баг в коде, но как понять, в какой момент JavaScript начал что-то неправильно считать? Правильно, оборачиваем эту радость тестами на тип переменной, это же очень просто Идем во вкладку Sources в инструментах разработчика. Откройте файл code.js . У вас будут 3 части: первая слева, в которой отображается список файлов и вторая — в которой у нас отображается код. Но больше всего информации мы сможете почерпнуть из третьей части снизу, в которой отображается ход выполнения нашего кода. Давайте поставим breakpoint на 15 строчке (для этого надо щелкнуть по номеру строки в окне, где у нас отображается код, после чего у вас появится голубая метка). Перезапустите страницу, и введите любые значения в нашу программу.

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

Конструкция try… catch встречается во всех современных языках программирования. Зачем эта синтаксическая конструкция нужна практически? Дело в том, что при возникновении ошибки в коде, он останавливает свое выполнение на месте ошибки — и все, дальнейшие инструкции интерпретатор не исполнит. В реально работающем приложении, из нескольких сотен строчек кода, нас это не устроит. И предположим, что мы хотим перехватить код ошибки, передать разработчику ее код, и продолжить выполнение дальше.
Наша статья была бы неполной без краткого описания основных типов ошибки в JavaScript:
- Error — общий конструктор объекта ошибки.
- EvalError — тип ошибки, появляющийся во время ошибок исполнения eval() , но не синтаксических, а при неправильном использовании этой глобальной функции.
- RangeError — происходит, когда вы выходите за пределы допустимого диапазона в исполнении вашего кода.
- ReferenceError — происходит, когда вы пытаетесь вызвать переменную, функцию или объект, которых нет в программе.
- SyntaxError — ошибка в синтаксисе.
- TypeError — происходит при попытке создания объекта с неизвестным типом переменной или при попытке вызова несуществующего метода
- URIError — редко встречающий код, который возникает при неправильном использовании методов encodeURL и DecodeURL.
Давайте создадим самый простой калькулятор (даже калькулятором его называть громко, я бы сказал:«исполнитель введенных выражений»). Его интерактивный пример можно найти здесь. Хорошо, давайте теперь посмотрим на наш код:
Если вы попробуете ввести корректное математическое выражение, то все сработает нормально. Однако попробуйте ввести некорректное выражение, к примеру, просто строку, тогда программа выведет пользователю соответствующее предупреждение.
Надеюсь, вы прочитаете еще статьи, в которых объясняются другие части перехвата ошибок, такие например, как эта , чтобы расширить свое понимание в отладке программ, и изучите другие синтаксические конструкции, такие как finally , а также генерацию своих собственных ошибок.
На этом все. Надеюсь, эта статья оказалась полезна и теперь, при отладке приложений, вы будете чувствовать себя более уверенно. Мы разобрали типичные ошибки от самых элементарных, которые делают новички программирующие на JS всего несколько дней, до техники перехвата ошибок, которые применяют более продвинутые разработчики.
не работает скрипт
чтот не выполняется как задумано — через горячие клавиши в openbox.
В терминале выполняется, через dmenu выполняется… как надо.
и самое главное: на двух других ноутбуках всё работает.
по задумке должно включать и выключать тачпад:
если зачем то нужен кусок текста из rc.xml:
эта же команда — lcktch — нормально выполняется в терминале и через dmenu
Можно вопрос?
Зачем ты для этого делаешь скрипт, если обычно для отключения тачпада есть сочетание с Fn клавишей для этого? Или речь не о встроенном в ноутбук тачпаде, а о чем-то другом?
есть сочетание с Fn клавишей
два ноута HP, с разницей в возрасте пять лет, ни на одном нет такого сочетания. На всех остальных есть, да.
ну и WIN+U удобнее чем fn+F7, кмк =)
А ты перезапускал openbox после редактирования конфига или делал
openbox —reconfigure ?
Скрипт (по хоткею) либо включает, либо выключает тачпад. Но не переключает между состояниями. Нипанимат, почему так происходит.
в терминале переключает. Думал может зависит от юзера запустившего скрипт, но он бы тогда и на половину не работал бы…
Попробуй что-то другое забайндить на W-u и посмотри работает ли все без проблем, сравни переменные окружения интерактивной оболочки с теми, или прописаны в настройках dmenu с теми, которые инициализированы без оболочки и dmenu.
Может это сочетание клавиш уже чем-то занято? Лорчую совет попробовать другую комбинацию.
не, на других кнопках аналогично не работает.
сравни переменные окружения интерактивной оболочки с теми, или прописаны в настройках dmenu с теми, которые инициализированы без оболочки и dmenu
хм, как это сделать?
Попробуй что-то другое забайндить на W-u
всё ок. и в самом скрипте всё срабатывает как надо, кроме if\then\else
вот полный текст:
попробуй вывести все промежуточные значения в какой нибудь файл через echo "" > /file, подебажить короче

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

может отличаться наличием каких-то переменных
Обычно PATH не хватает.
У тебя шебанг неправильно написан.
Он может в терминале запускать с указанием шелла, вроде sh ./script.sh , а в конфиге опенбокса указание на шелл нет, а шебанг в скрипте написан с ошибкой.
Но тогда бы вообще ничего не выполнялось, а у него какой-то эффект был, по его словам. Да и в dmenu он писал, что работает. А что происходит при неправильном shebang? По идее вообще не запускается или может выполниться вместо bash другой Шелл?
Запускается sh. Если он не линк на bash или еще какой шелл, то он в его случае захлебнется, потому что синтаксис не посиксовый.
У тебя шебанг неправильно написан.
вот это вот выводит на экран все две переменные.
да, .sh не запускаются там. Поэтому линк в /home/user/bin и всё работало на других буках.
Из dmenu lcktch запускается и работает,
из терминала lcktch запускается и работает.
По хоткею lcktch запускается, курсор переводится в правый нижний угол, на экран выводятся ID и $x. Но не срабатывает if\then\else если строки поменять местами он выключить тачпад, если еще раз поменять то включит. Но не переключает между состояниями.
Курсы javascript
jQuery там подключается внизу страницы, версия jquery-3.4.1.min.js, в примере тоже "min", только более ранняя.
Поменял их местами, но всё равно не работает.
А не могут там другие javascript конфликтовать с jQuery? Там всякие метрики, счётчики и т.п. есть.
Добавил как советуют в stackoverflow:
Но всё равно не работает. Причём там советуют ставить script в head, а у меня используется bootstrap 4, который рекомендует ставить его вниз страницы. Пробовал оба варианта, всё равно счётчик не считает.
Смотрите консоль, какие ошибки выдает
И jquery и скрипты bootstrap лучше ставить в head.
То, что я сейчас вижу на вашей странице
У вас сначала идет вызов
А потом где то далеко внизу идет вызов библиотеки jquery, в которой и определяются функции jQuery (и $)
Естественно возникает ошибка
Uncaught ReferenceError: jQuery is not defined
но не работает. Насколько я понимаю, как-то не так jQuery определён именно в скрипте, а не в конце страницы.
На этой же странице используются функции jQuery, которые и выше в HTML коде и работают прекрасно. Может быть в них проблема? Там тоже есть $. Вот:
И оно работает. А счётчик нет.
Уясните, как работает браузер.
Он начинает читать текст сверху вниз.
Если он встречает теги html, то он строит дерево dom.
Если встречает link, то загружает его и строит таблицы стилей.
Если встречает <style src=. >, то загружает файл и выполняет его
Если встречает <style>. </style>, то просто выполняет его.
Все строго сверху вниз.
Когда все построено, и скрипты загружены и выполнены, возникает событие ‘DOMContentLoaded’. Именно по нему работает функция jquery().ready().
Но, что бы вызвать эту функцию браузер должен знать, что она вообще существует, и как ее выполнять.
Эта функция описана в библиотеки jquery, которую вы вызываете где то в конце
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
До того, как этот файл загрузится и отработает, браузер понятия не имеет, что существует какая то там функция jQuery (или $()).
И любое обращение к ним вызовет ошибку.
По мне, так это дурацкое занятие, размещать скрипты в теле html.
Все скрипты в head.
Те, которые должны вызываться после загрузки — в обработчик DOMContentLoaded
Ошибка скрипта: что это такое и как это исправить

Ошибки сценария могут быть трудно определить, потому что они не очень описательны. Они специально спроектированы таким образом из соображений безопасности, но вам не нужно знать, почему произошла ошибка сценария, чтобы решить проблему. Большинство сообщений об ошибках скрипта вызвано использованием устаревшего веб-браузера, такого как Internet Explorer , но есть ряд других исправлений, если вы используете современный браузер.
Как появляются сообщения об ошибках скрипта
Когда возникает ошибка скрипта, вы обычно видите сообщение вроде этого:
Причина появления сообщений об ошибках скрипта
Сообщения об ошибках в скриптах чрезвычайно туманны, поэтому существует множество причин, которые могут их вызвать. Самый простой способ понять ошибки скрипта — это знать, что они указывают на то, что скрипт на веб-сайте, который вы пытаетесь использовать, каким-то образом неисправен. Возможно, он не работает, не работает во время работы, завис или может произойти что-то еще полностью.
В большинстве случаев вам не нужно знать, почему произошла ошибка скрипта, чтобы исправить это. У вас либо есть какая-то проблема с вашим веб-браузером, которую вы можете исправить, либо сам скрипт сломан, но вы не можете это исправить.
Если вы используете Internet Explorer, причина появления ошибок сценария, вероятно, связана с тем, что Internet Explorer был заменен Edge. Microsoft настоятельно рекомендует вам перейти на Edge , но переход на Chrome, Firefox или любой другой современный браузер будет иметь тот же эффект.
Как исправить ошибку скрипта
В некоторых случаях лучший ответ на ошибку скрипта — просто игнорировать ее. Если вы выберете OK или Отмена в сообщении об ошибке, и веб-сайт продолжит загружаться без каких-либо обнаруживаемых проблем, то ошибка скрипта — это скорее небольшая неприятность, чем то, о чем вам действительно нужно беспокоиться.
Когда ошибка скрипта мешает функционированию веб-сайта или эти ошибки становятся слишком неприятными, есть несколько шагов, которые можно предпринять, чтобы решить проблему.
Чтобы исправить ошибку сценария, вы должны сначала определить, является ли проблема вашей целью, или это проблема с веб-сайтом. Если это проблема с сайтом, вы не сможете исправить это самостоятельно.
Если это проблема с вашей стороны, то обновление веб-браузера, переключение на другой веб-браузер или изменение некоторых настроек в вашем браузере обычно решит проблему.
Попробуйте загрузить веб-страницу еще раз. Ошибки скрипта, особенно ошибки, указывающие на то, что запуск скрипта занимает слишком много времени, иногда устраняются, если вы просто перезагрузите веб-страницу. Если ошибка не повторяется, вам не о чем беспокоиться. Если он продолжает возвращаться, возможно, проблема в вашем веб-браузере.
- Чтобы принудительно перезагрузить веб-страницу в Windows: удерживайте Ctrl + F5 .
- Для того, чтобы заставить веб — страницу для перезагрузки на MacOS: Удержание Ctrl + Shift + R .
Обновите свой веб-браузер. Устаревшие веб-браузеры иногда взаимодействуют со сценариями неожиданным образом, что приводит к ошибкам. Так как в любом случае из-за проблем с безопасностью рекомендуется обновлять ваш веб-браузер, это одно из первых исправлений, которое вам следует попробовать. Обновление Google Chrome или Firefox довольно просто.
Microsoft Edge обновляется автоматически вместе с Windows. Если у вас возникли проблемы с Центром обновления Windows, существуют другие способы обновления Windows .
Попробуйте загрузить другие веб-страницы. Это простой способ проверить, локализована ли проблема на одном веб-сайте. Если вы видите ошибки сценариев на одном веб-сайте, возможно, существует проблема со сценариями на этом веб-сайте, и вы ничего не можете с этим поделать. Если вы видите ошибки сценариев на многих веб-сайтах, возможно, проблема в вашем веб-браузере.
Переключитесь на другой веб-браузер . Это еще один простой, но важный шаг, который может помочь сузить источник проблемы. Если веб-страница нормально загружается в другом браузере, то возникает проблема с первым браузером. Вы можете изменить браузер по умолчанию в Windows, а также в MacOS .
В некоторых случаях, просто использование другого браузера, который не создает ошибки скрипта, является лучшим и самым простым вариантом. Это особенно верно, если вы используете более не поддерживаемый браузер, такой как Internet Explorer.
Попробуйте загрузить веб-страницу с другого устройства. Это хороший способ определить, является ли проблема вашей целью или нет. Если вы видите ошибку сценария при посещении веб-страницы на своем компьютере, но не видите ее при посещении этой страницы с помощью телефона, компьютера друга или другого устройства, то проблема на вашей стороне.
Если вы видите одну и ту же ошибку на нескольких устройствах, возможно, существует проблема с веб-сайтом, который вы пытаетесь посетить. В этом случае все, что вы можете сделать, это подождать, пока веб-мастер решит проблему.
Удалить временные интернет-файлы . Если у вас повреждены файлы интернет-кэша на вашем компьютере, вы можете столкнуться с ошибками сценария. В большинстве случаев простая очистка кэша вашего веб-браузера решит эту проблему.
Отключите ваши плагины . Когда что-то идет не так, возможно непредвиденное взаимодействие между плагином и веб-сайтом, чтобы помешать правильной работе скрипта.
Если ошибка вашего скрипта исчезла после отключения ваших плагинов, включите их по одному, чтобы определить, какой плагин вызывает проблему. Вы можете либо продолжить использовать плагин и жить с ошибкой скрипта, либо прекратить использование этого плагина, пока разработчик не исправит проблему.
Отключить аппаратное ускорение. Аппаратное ускорение — это функция, которая позволяет вашему веб-браузеру задействовать всю мощь вашей видеокарты. В некоторых случаях включение этой функции нарушит работу определенных сценариев. Отключение позволяет этим скриптам работать нормально. Вы можете отключить аппаратное ускорение в Chrome и отключить аппаратное ускорение в Firefox .
Сбросьте настройки безопасности браузера или сбросьте настройки браузера. В некоторых случаях ненормально высокие параметры безопасности в вашем веб-браузере могут мешать работе сценариев. Если у вас нет конкретной причины для того, чтобы установить высокий уровень безопасности, попробуйте сбросить уровень безопасности.
Если это не сработает, вы также можете просто сбросить настройки браузера сразу. Вы можете быстро восстановить Chrome до его состояния по умолчанию, обновить Firefox , сбросить Microsoft Edge и сбросить Safari .
Ждите вебмастера. Если вы по-прежнему сталкиваетесь с ошибками сценария после выполнения всех этих исправлений, скорее всего, существует проблема со сценарием на веб-сайте, который вы пытаетесь использовать. Это особенно вероятно, если вы видите ошибку сценария только при посещении определенного веб-сайта или веб-сайтов. Поскольку это вне вашего контроля, вам просто нужно подождать, пока веб-мастер веб-сайта решит проблему.