Ошибки JavaScript делятся на три отчётливые категории - синтаксис, runtime и логика, - и подходящий инструмент для поиска каждой свой. Проверка синтаксиса находит структурные проблемы до того, как движок даже запустит ваш код; декодер ошибок runtime объясняет загадочные сообщения после их появления; статический анализатор находит потенциальные баги, которых не касается ни тот ни другой подход. Это руководство сопоставляет каждую категорию ошибок JavaScript с лучшим инструментом для её обнаружения, с процессами для браузера, Node.js и CI/CD-пайплайнов.
Виды ошибок JavaScript
Каждая встреченная вами ошибка JavaScript относится к одной из трёх категорий, и их смешение ведёт к выбору неверного инструмента. Сначала понять категории - значит серьёзно сэкономить время отладки, ведь это точно указывает, где искать и какая проверка поможет.
Ошибки синтаксиса
Ошибки синтаксиса находит парсер JavaScript до выполнения хоть одной строки кода. Они означают, что движок не может интерпретировать структуру файла - отсутствующая закрывающая скобка, неожиданный токен, зарезервированное слово в качестве имени переменной или незакрытый строковый литерал. Ошибка выбрасывается на этапе разбора с номером строки и кратким описанием. Проверка или валидация синтаксиса находит их без запуска кода.
Ошибки runtime
Ошибки runtime выбрасываются во время выполнения, когда синтаксически корректный код пытается выполнить недопустимую операцию. Самые частые: обращение к свойству у `null` или `undefined` (`TypeError`), вызов того, что не является функцией (`TypeError`), обращение к несуществующей переменной (`ReferenceError`) или деление на нечисловое значение (`NaN` - который тихо проваливается). Для обнаружения этих ошибок нужна работающая среда, декодер stack trace или аккуратный статический анализ.
Ошибки логики
Ошибки логики выдают неверный результат, вообще не выбрасывая ошибок - цикл со сдвигом на единицу, неверное условие, мутация там, где задумывалась копия. Ни один валидатор или проверка синтаксиса их не находит; нужны юнит-тесты, код-ревью или сессия с отладчиком. Набор правил ESLint пересекается с некоторыми паттернами логических ошибок (например, помечает `==` вместо `===`), но большинство логических багов находится только запуском кода на реальных данных.
- SyntaxError: Обнаруживается при разборе - отсутствующая скобка, неверный токен, незакрытая строка.
- TypeError: Обращение к `.property` у null/undefined, вызов не-функции.
- ReferenceError: Использование переменной, никогда не объявленной в текущей области видимости.
- RangeError: Передача значения вне допустимого диапазона - напр. `new Array(-1)`.
- URIError: Некорректный URI, переданный в `decodeURIComponent` или `encodeURIComponent`.
- Логический баг: Неверный вывод, ошибки нет - нужны тесты или отладчик.
Note
Проверки синтаксиса JavaScript
Проверка синтаксиса JavaScript (её также называют валидатором синтаксиса) разбирает ваш код без выполнения и сообщает о каждом месте, где структура нарушает грамматику JavaScript. Это самая быстрая и безопасная первая проверка - она находит ошибки, из-за которых ваш код вообще не запустился бы, и делает это за миллисекунды без побочных эффектов.
Когда использовать проверку синтаксиса
Проверки синтаксиса полезны в четырёх ситуациях: когда вы получаете JavaScript от третьей стороны (сгенерированный файл, фрагмент из документации или вставленный коллегой код), когда вы отлаживаете скрипт, который тихо падает в минифицированной сборке, когда вы пишете JavaScript в редакторе без поддержки language server, и когда вам нужна быстрая проверка здравости перед коммитом сильно правленного файла.
Что проверка синтаксиса находит, а что нет
| Проверка | Валидатор синтаксиса | ESLint | Компилятор TypeScript |
|---|---|---|---|
| Отсутствует закрывающая скобка | ✓ Да | ✓ Да | ✓ Да |
| Неожиданный токен / неверный синтаксис | ✓ Да | ✓ Да | ✓ Да |
| Ссылка на неопределённую переменную | ✗ Нет | ✓ С правилом no-undef | ✓ Да (strict) |
| Несовпадение типов | ✗ Нет | ✗ Нет | ✓ Да |
| Предупреждение о неиспользуемой переменной | ✗ Нет | ✓ no-unused-vars | ✓ noUnusedLocals |
| Отсутствует await у async-вызова | ✗ Нет | ✓ no-floating-promises | ✓ Да |
| Логика / неверный вывод | ✗ Нет | ✗ Нет | ✗ Нет |
Валидатор синтаксиса JavaScript на Aback Tools работает полностью в вашем браузере - вставьте код, нажмите «проверить», и каждая синтаксическая ошибка будет подсвечена с номером строки и сообщением парсера меньше чем за секунду. Ваш код никогда не загружается на сервер, что делает инструмент безопасным для проприетарных скриптов, внутренних инструментов и конфиденциального кода приложений.
Валидатор синтаксиса JavaScript
Мгновенно проверяйте JavaScript-код на синтаксические ошибки - локальный в браузере парсер, диагностика по строкам, без загрузки файлов.
Ошибки runtime и stack traces
Ошибки runtime приходят как выброшенное исключение с типом, сообщением и stack trace. Умение эффективно их читать отличает быстрых отладчиков от медленных. Тип ошибки сразу сужает причину; stack trace указывает точный путь выполнения, который к ней привёл.
Как читать stack trace JavaScript
Stack trace - это список вызовов функций в обратном порядке - самый недавний вызов вверху, точка входа внизу. Каждая строка показывает имя функции, путь к файлу и номер `line:column`. Начните с верха trace и спускайтесь, пока не найдёте первую строку, ссылающуюся на ваш собственный код (не на библиотеку вроде React, Express или lodash). Это вызов, который вызвал ошибку. Строки выше показывают, как вы туда попали.
TypeError: Cannot read properties of undefined (reading 'name')
at formatUser (app.js:24:18) // ← ваш код - начните здесь
at renderCard (components.js:51:5) // ← ваш код - цепочка вызовов
at Array.map (<anonymous>)
at buildList (components.js:44:20)
at App (app.js:12:15)
at React.createElement ...Первая строка называет тип ошибки (`TypeError`) и конкретное свойство, с которым произошёл сбой (`name`). Строка `app.js:24:18` - место, где произошло обращение к свойству. Перейдите к этой строке - `user.name`, где `user` undefined, - и добавьте подходящую защиту: optional chaining (`user?.name`), проверку на null или значение по умолчанию. Объяснитель stack trace JavaScript разбирает любой stack trace и автоматически выдаёт структурированную расшифровку происхождения, цепочки вызовов и наиболее вероятного исправления.
Расшифровка загадочных сообщений об ошибках runtime
Некоторые сообщения об ошибках runtime понятны сразу; другие печально известны своей бесполезностью. `"Maximum call stack size exceeded"` - бесконечная рекурсия. `"Cannot set properties of null"` - вы вызвали `.setAttribute()` или подобное у элемента DOM, который ещё не существует. `"$ is not defined"` в контексте браузера - jQuery не был загружен до скрипта, который его использует. Декодер ошибок runtime JavaScript принимает любое сообщение об ошибке и возвращает понятное объяснение с конкретными шагами исправления для самых частых паттернов.
Tip
Декодер ошибок runtime JavaScript
Вставьте любое сообщение об ошибке JavaScript и получите понятное объяснение с адресными рекомендациями по исправлению - без настройки окружения.
ESLint и статический анализ
ESLint - стандартный для индустрии инструмент статического анализа для JavaScript и TypeScript. Он читает ваш исходный код без выполнения и применяет настраиваемый набор правил, который находит проблемы от синтаксических ошибок до антипаттернов безопасности. В отличие от проверки синтаксиса, ESLint понимает области видимости, жизненные циклы переменных и графы импортов - что позволяет ему находить баги, невидимые для чистого парсера.
Что ESLint находит, а проверки синтаксиса упускают
- Неопределённые переменные: Правило `no-undef` помечает любую переменную, используемую без объявления в области видимости.
- Неиспользуемые переменные: `no-unused-vars` предотвращает накопление мёртвого кода, заслоняющего реальную логику.
- Небезопасное равенство: `eqeqeq` требует `===` вместо `==`, устраняя баги приведения типов.
- Отсутствует await: `no-floating-promises` (через TypeScript ESLint) ловит необработанные async-вызовы.
- Недостижимый код: `no-unreachable` помечает инструкции после `return` или `throw`.
- Без console в проде: `no-console` не даёт отладочным логам попасть в продакшен.
- Правила безопасности: `eslint-plugin-security` помечает потенциальные уязвимости инъекций и небезопасные regex.
Основы конфигурации ESLint
Поведение ESLint полностью управляется его файлом конфигурации - `.eslintrc.json`, `.eslintrc.js` или новым flat config-форматом `eslint.config.js`. Конфигурация объявляет, какие наборы правил расширять (`eslint:recommended`, `plugin:@typescript-eslint/recommended`, `plugin:react/recommended`) и какие отдельные правила включать, выключать или настраивать. Неверно настроенный файл ESLint может тихо отключить важные правила - вот почему валидация самой конфигурации важна. Валидатор конфигурации ESLint проверяет ваш файл конфигурации на структурные ошибки и конфликты правил до запуска проверки lint.
Ценность ESLint не в правилах, которые вы включаете, - она в правилах, которые ваша команда договорилась применять последовательно. Общий конфиг в системе контроля версий гарантирует, что каждый разработчик видит одинаковый отклик.
Первый запуск ESLint
# Установить ESLint в проект
npm install --save-dev eslint
# Интерактивно инициализировать файл конфигурации
npx eslint --init
# Проверить один файл
npx eslint src/app.js
# Проверить каталог и автоисправить безопасные проблемы
npx eslint src/ --fix
# Вывод JSON для CI-инструментов
npx eslint src/ --format json > eslint-report.jsonNote
Отладка через DevTools браузера
Chrome DevTools, Firefox Developer Tools и Safari Web Inspector предоставляют самый глубокий доступный опыт отладки JavaScript - живое выполнение, точки останова, инспекцию переменных и трассировку сетевых запросов. Для ошибок runtime, которые трудно воспроизвести локально, DevTools - основная среда исследования.
Панель Console
Вкладка Console показывает каждое залогированное сообщение, предупреждение и выброшенную ошибку в реальном времени. Ошибки отображаются красным с раскрываемым stack trace. Клик по ссылке файл:строка справа перепрыгивает прямо в панель Sources в это место. Классификатор ошибок консоли браузера дополняет DevTools, категоризируя ошибки консоли по типу и серьёзности - полезно, когда вывод консоли длинный и нужно быстро расставить приоритеты.
Точки останова и панель Sources
Панель Sources позволяет ставить точки останова - приостанавливать выполнение на конкретной строке и инспектировать каждую переменную в области видимости в этот момент. Кликните в поле номера строки в панели Sources, чтобы поставить breakpoint, затем перезагрузите страницу или вызовите действие, вызывающее ошибку. Когда выполнение приостановлено, наведите курсор на любую переменную, чтобы увидеть её текущее значение, используйте панель Call Stack, чтобы увидеть, как вы туда попали, и шагайте по коду с F10 (шаг с обходом) или F11 (шаг внутрь).
Условные точки останова и logpoints
Кликните правой кнопкой по любому номеру строки в Sources, чтобы добавить условную точку останова (пауза только когда условие истинно, напр. `user.id === 42`) или logpoint (логирует значение без паузы, как ненавязчивый `console.log`). Оба крайне полезны для отладки циклов и обработчиков событий, где пауза на каждой итерации была бы непрактична.
| Подход к отладке | Лучше всего для | Ловит ошибки runtime | Ловит ошибки синтаксиса |
|---|---|---|---|
| Валидатор синтаксиса JavaScript | Статическая проверка до запуска | ✗ Нет | ✓ Да |
| ESLint | Статический анализ, CI/CD | ⚠ Частично | ✓ Да |
| Консоль DevTools браузера | Живые ошибки браузера | ✓ Да | ✓ Да |
| Точки останова DevTools | Интерактивная отладка | ✓ Да | ✗ Нет |
| Декодер ошибок runtime | Объяснение сообщений об ошибках | ✓ Да | ✗ Нет |
| Объяснитель stack trace | Отслеживание источника вызова | ✓ Да | ✗ Нет |
| Node.js --inspect + Chrome | Отладка на стороне сервера | ✓ Да | ✓ Да |
Проверка ошибок в CI/CD
Ручная проверка ошибок во время разработки - хорошая практика, но не гарантия. Автоматизация проверки ошибок JavaScript в вашем CI/CD-пайплайне гарантирует, что ни синтаксическая ошибка, ни нарушение ESLint, ни ошибка типов не попадут в основную ветку - независимо от того, какой разработчик отправил pull request и запускал ли он проверки локально.
Минимальные ворота качества CI
name: JavaScript Quality
on:
pull_request:
paths: ['src/**/*.js', 'src/**/*.ts']
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: ESLint
run: npx eslint src/ --max-warnings 0
- name: TypeScript check
run: npx tsc --noEmitФлаг `--max-warnings 0` трактует предупреждения ESLint как ошибки, блокируя слияние. В проектах TypeScript добавьте к этому `tsc --noEmit`, чтобы ловить ошибки типов, которые правила ESLint не видят. Оба шага завершаются ненулевым кодом при сбое, что валит workflow GitHub Actions и не даёт вмержить pull request, пока проблемы не решены.
Source maps для отслеживания ошибок в проде
Когда ошибка JavaScript доходит до продакшена в минифицированном бандле, stack trace показывает сжатые имена файлов и номера столбцов, бесполезные без source map. Source maps связывают минифицированный вывод с исходными файлами. Перед деплоем проверьте через Валидатор source map, что ваши файлы source map корректно структурированы, - сломанная source map порождает нечитаемые продовые stack traces и заметно замедляет диагностику инцидентов.
Warning
Лучшие практики отладки
Хорошие привычки проверки ошибок сокращают время отладки на порядки. Эти практики применимы, работаете ли вы в браузере, сервисе Node.js или serverless-функции.
Исправляйте первую ошибку, а не все
Синтаксические ошибки JavaScript каскадируются - одна отсутствующая скобка в строке 10 может породить пять ошибок ниже, пока парсер теряет структуру документа. Всегда сначала исправляйте самую верхнюю из найденных ошибок, затем перезапускайте валидатор. То, что выглядело как пять багов, часто одно. Это равно применимо к отчётам ESLint и выводу компилятора TypeScript.
Используйте строгий режим и современные возможности языка
Добавление `"use strict"` в файл (или использование ES-модулей, которые всегда строги) превращает тихие сбои в выброшенные ошибки. Присваивание необъявленной переменной в небрежном режиме тихо создаёт глобальную переменную; в строгом режиме сразу выбрасывается `ReferenceError`. Optional chaining (`?.`), nullish coalescing (`??`) и значения по умолчанию в деструктуризации массивов (`const [a = 0] = arr`) заметно сокращают область появления ошибок `TypeError: Cannot read properties of undefined`.
Валидируйте внешние данные на границе
Большинство `TypeError` в продакшене приходит из внешних данных - ответов API, пользовательского ввода или значений localStorage, - не соответствующих ожидаемой форме. Валидируйте входящие данные на границе: используйте валидатор схемы вроде Zod или Joi для ответов API, проверяйте значения `localStorage` перед парсингом их как JSON и никогда не считайте поле существующим только потому, что оно было в тестовых данных. Калькулятор размера heap JavaScript полезен при появлении ошибок памяти - он помогает оценить, не превышает ли большая структура данных или долгоживущий процесс выделение heap у V8.
- Сначала исправьте первую ошибку: Синтаксические ошибки каскадируются - одна реальная проблема порождает несколько найденных.
- Включите ESLint в редакторе: Отклик в реальном времени находит ошибки при наборе, а не после коммита.
- Используйте TypeScript: Ошибки типов, найденные на компиляции, не могут стать ошибками runtime в проде.
- Валидируйте внешние данные: Ответы API и пользовательский ввод должны проверяться до использования, а не считаться корректными.
- Пишите адресные тесты: Юнит-тесты критических путей выявляют логические ошибки, которые не найдёт ни один статический инструмент.
- Используйте source maps: Читаемые продовые stack traces резко сокращают время реакции на инциденты.
Tip
Key takeaways
- Ошибки синтаксиса ловятся до выполнения - используйте Валидатор синтаксиса JavaScript для мгновенной, локальной в браузере проверки без загрузки кода.
- Ошибки runtime дают тип и stack trace - Декодер ошибок runtime JavaScript объясняет любое сообщение об ошибке понятным языком с шагами исправления.
- ESLint находит проблемы, которые упускают проверки синтаксиса: неопределённые переменные, небезопасное равенство, неиспользуемые импорты и отсутствующий `await` - проверьте свою конфигурацию ESLint через Валидатор конфигурации ESLint.
- Всегда сначала исправляйте самую верхнюю найденную ошибку - синтаксические ошибки каскадируются, и одна реальная проблема порождает несколько найденных.
- Добавьте ESLint и `tsc --noEmit` в свой CI/CD-пайплайн, чтобы ни одна ошибка не вмержилась незамеченной, независимо от локальной настройки.
- Source maps необходимы для читаемых продовых stack traces - проверьте их через Валидатор source map перед деплоем.
- Валидируйте внешние данные (ответы API, пользовательский ввод) на границе, чтобы устранить главную причину `TypeError: Cannot read properties of undefined` в продакшене.