Learn JavaScript

Отладка: breakpoints, debugger, чтение ошибок

Ошибки в JavaScript чаще всего чинятся не “угадыванием”, а отладкой: понять, где код оказался не таким, как ожидалось, и почему. Для этого нужны две вещи:

  • уметь читать ошибку (сообщение + строка + stack trace)
  • уметь остановить выполнение и посмотреть значения (breakpoint, debugger)

1) Как читать ошибку в консоли

Типичное сообщение в DevTools выглядит так:

  • тип ошибки (например, ReferenceError, TypeError)
  • сообщение (что произошло)
  • файл:строка:колонка
  • stack trace (цепочка вызовов, как код дошел до ошибки)

Пример:

  • TypeError: Cannot read properties of null (reading 'textContent')
  • main.js:12

Смысл:

  • где-то вызывается .textContent, но значение слева - null
  • значит, элемент не найден (querySelector вернул null) или переменная потеряла значение

2) Самые частые типы ошибок и что они означают

ReferenceError

Переменная не объявлена или нет в текущей области видимости.

console.log(count);

TypeError

Операция применяется не к тому типу (часто - вызвали не функцию, или попытались читать свойство у null/undefined).

const el = null;
console.log(el.textContent);

SyntaxError

Синтаксис неверный: пропущена скобка, запятая, кавычка.

const a = ;

3) Stack trace: почему он важнее, чем первая строка кода

Если ошибка возникла глубоко в функции, stack trace покажет путь.

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

Мини-пример:

function formatUser(user) {
  return user.name.toUpperCase();
}

function render(user) {
  return formatUser(user);
}

render(null);

Ошибка будет в formatUser, но причина может быть в том, что render передал null.

4) Breakpoints: остановка на нужной строке

Breakpoint - это точка останова в DevTools, где выполнение останавливается и можно посмотреть:

  • значения переменных
  • call stack
  • область видимости (Scope)
  • выполнить выражения в Console

Где обычно ставить breakpoint:

  • перед строкой, где “что-то стало не так”
  • в начале обработчика события
  • перед return в функции, которая дает неправильный результат

5) Пошаговое выполнение: step over / step into / step out

Во время остановки доступны действия:

  • Step over - выполнить текущую строку и перейти дальше (не заходя внутрь функций)
  • Step into - зайти внутрь вызванной функции
  • Step out - выйти из текущей функции до места, где она была вызвана
  • Resume - продолжить выполнение до следующего breakpoint

Это основной способ понять, на каком шаге переменная получила неожиданное значение.

6) debugger: точка останова прямо в коде

Иногда проще поставить точку останова кодом, особенно если:

  • код генерируется
  • нужно остановиться внутри условия
  • breakpoint трудно поймать
function calcTotal(items) {
  let total = 0;

  for (const item of items) {
    if (item.price < 0) {
      debugger;
    }

    total += item.price;
  }

  return total;
}

debugger; сработает только когда DevTools открыт. После отладки его обычно удаляют.

7) Watch и проверка выражений

Watch (или “наблюдаемые выражения”) помогает следить за важными значениями, например:

  • items.length
  • user?.name
  • state.mode

Если Watch показывает, что значение стало неправильным, легко понять, на каком шаге это произошло, отматывая стек и шаги.

8) Console.log: как использовать в отладке, чтобы не утонуть

console.log полезен, но лучше использовать его как “маркер”, а не как бесконечный поток.

Примеры аккуратных логов:

console.log("loaded items:", items.length);
console.log("minPrice:", minPrice);
console.log("selected id:", id);

Для группировки удобно:

console.group("render");
console.log("items:", items);
console.log("filtered:", filtered);
console.groupEnd();

9) Два типовых сценария: как искать причину

Сценарий A: “ничего не работает” после клика

Обычно ошибка в обработчике события или в DOM-селекторе.

Что делать:

  • открыть Console и посмотреть ошибку
  • перейти по ссылке file:line
  • проверить, что querySelector не вернул null
  • поставить breakpoint в начале обработчика и пройти шагами

Мини-проверка:

const btn = document.querySelector("#save");
const input = document.querySelector("#name");

btn.addEventListener("click", () => {
  console.log("click");
  console.log("input:", input);
});

Сценарий B: “данные есть, но отображается неправильно”

Обычно проблема в логике: фильтр, сортировка, преобразование.

Что делать:

  • поставить breakpoint перед render
  • посмотреть входные данные и результат преобразования
  • проверить границы циклов и условия

Пример:

function filterByMin(items, min) {
  return items.filter((x) => x.price >= min);
}

Если min - строка, сравнение может вести себя неожиданно. Тогда нужен Number:

const min = Number(input.value) || 0;

10) Что стоит запомнить

  • Ошибка в консоли - это карта: тип, сообщение, строка, stack trace.
  • Breakpoint и пошаговое выполнение быстрее, чем догадки.
  • debugger; полезен, когда точку останова удобнее поставить кодом.
  • Частые причины: null вместо элемента, undefined в данных, строка вместо числа, неправильный путь выполнения.