Отладка JavaScript: как находить и исправлять ошибки
Методы отладки JavaScript
Ошибки в JavaScript - неизбежная часть разработки. Давайте рассмотрим основные способы их обнаружения и исправления, от простых логов до продвинутых инструментов.
Как найти ошибку с помощью DevTools?
Самый эффективный способ отладки - использование инструментов разработчика браузера (Chrome DevTools, Firefox Developer Tools и другие).
function multiply(a, b) {
debugger;
return a * b;
}
console.log(multiply(2, '3'));Js ошибка (ошибка javascript)
Шаги: Откройте DevTools (F12), перейдите на вкладку Sources, найдите файл с кодом, поставьте breakpoint на строке debugger или щёлкните по номеру строки. Выполнение остановится, и вы увидите Scope (локальные переменные) и Call Stack (стек вызовов). Переменная a равна 2, b равно '3' - результат будет строкой '23', а не числом 6.
Проблема: Breakpoint может не сработать, если код загружен динамически (через eval или import). Для таких случаев используйте ключевое слово debugger прямо в коде. Также при использовании обфусцированного или минифицированного кода включите Source Maps.
Как быстро вывести значения переменных?
Самый простой способ - добавить console.log в нужные места.
const result = fetchData();
console.log('Результат:', result);
if (result.length > 0) {
console.table(result[0]); // вывод объекта в виде таблицы
} else {
console.warn('Пустой ответ');
}
Цель: быстро проверить значения без остановки выполнения. Плюсы - простота, минусы - засорение консоли, необходимость удалять логи перед продакшеном.
Проблема: Если логов много, сложно найти нужный. Используйте console.group для группировки или заведите специальную функцию-логгер.
Как предотвратить падение скрипта при ошибке?
Конструкция try/catch позволяет обработать исключения и продолжить выполнение.
try {
JSON.parse('невалидный json');
} catch (e) {
console.warn('Ошибка парсинга:', e.message);
// можно предпринять альтернативные действия
}
Цель: обернуть потенциально опасный код (парсинг, работа с API, математические операции) и корректно обработать ошибку. catch получает объект ошибки с полями name, message, stack.
Проблема: try/catch не ловит асинхронные ошибки (setTimeout, Promise, callbacks). Для промисов используйте .catch() или try/catch внутри async функции. Также не стоит злоупотреблять - каждая обёртка добавляет накладные расходы.
Как отловить ошибку в Promise?
Для асинхронных операций (fetch, Promise) используйте .catch() или try/catch внутри async функций.
async function getData() {
try {
const response = await fetch('/api');
const data = await response.json();
} catch (err) {
console.error('Сетевая ошибка:', err.message);
}
}
Цель: обработка ошибок в цепочках промисов. Если не добавить .catch(), ошибка станет unhandled rejection и может привести к неожиданному поведению.
Проблема: Легко забыть добавить catch. В Node.js глобальный обработчик process.on('unhandledRejection', ...) перехватит такие ошибки. В браузере они выводятся в консоль, но не прерывают выполнение.
Как избежать ошибок до выполнения кода?
Статические анализаторы (линтеры), такие как ESLint, находят потенциальные ошибки на этапе написания кода.
// .eslintrc.json
{
"rules": {
"no-undef": "error",
"no-unused-vars": "warn"
}
}
Команда: npx eslint app.js выведет все найденные проблемы. Линтер проверяет синтаксис, неиспользуемые переменные, опасные конструкции.
Цель: предотвратить опечатки, использование необъявленных переменных, и т.д. Интегрируйте линтер в редактор (VSCode) и CI/CD.
Проблема: Линтер не обнаруживает логические ошибки и проблемы времени выполнения (например, undefined is not a function). Настраивайте правила под конкретный проект, чтобы избежать ложных срабатываний.
Расширенные примеры с типичными ошибками и способами их отладки.
// Пример 1: ReferenceError - необъявленная переменная
function test() {
console.log(notDefined);
}
test();
Uncaught ReferenceError: notDefined is not defined
at test (app.js:2)
at app.js:5
Ошибка говорит об отсутствии переменной. Решение: объявить через let/const или проверить через typeof.
// Пример 2: TypeError - чтение свойства у undefined
const obj = {};
console.log(obj.data.name);
Uncaught TypeError: Cannot read properties of undefined (reading 'name')
at app.js:2
Решение: использовать опциональную цепочку obj.data?.name или проверку if (obj.data).
// Пример 3: Необработанный промис (unhandled rejection)
async function fail() {
throw new Error('Async fail');
}
Promise.resolve().then(() => fail()).then(() => console.log('success'));
Uncaught (in promise) Error: Async fail
at fail (app.js:2)
at app.js:4
Ошибка не перехвачена. Добавьте .catch(err => console.error(err)) в конец цепочки.
// Пример 4: Использование console.trace() для отслеживания стека
function one() { two(); }
function two() { three(); }
function three() { console.trace('Вызвана three'); }
one();
Вызвана three console.trace @ app.js:4 three @ app.js:4 two @ app.js:3 one @ app.js:2 (anonymous) @ app.js:6
Полезно для понимания последовательности вызовов, особенно при рекурсии или замыканиях.
// Пример 5: Глобальный обработчик unhandledRejection в Node.js
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
async function fail() { throw new Error('error'); }
fail(); // без .catch()
Unhandled Rejection at: Promise { <rejected> Error: error } reason: Error: error
Это защитный механизм на продакшн-сервере. Все необработанные промисы будут зафиксированы.