Перейти к содержимому
Тема 16 из 16
Теория

Ошибки и JSON

Зачем это нужно

Программы ломаются: пользователь ввёл буквы вместо числа, сервер прислал испорченные данные, файла нет. Без обработки одна такая ошибка останавливает всю программу. Конструкция try … catch позволяет поймать ошибку и решить, что делать: показать сообщение, взять значение по умолчанию, попробовать снова.

А JSON — главный формат обмена данными в вебе: в нём приходят ответы сервера, хранятся настройки. Разбор «чужого» JSON — самое частое место, где нужна обработка ошибок, поэтому эти темы вместе.

Что такое ошибка

console.log("начало");
const user = null;
console.log(user.name);   // TypeError — программа здесь остановится
console.log("конец");     // не выполнится

Вывод:

начало
TypeError: Cannot read properties of null (reading 'name')

Самые частые виды ошибок:

Ошибка Когда
SyntaxError код записан не по правилам (или испорчен JSON)
ReferenceError обращение к несуществующей переменной
TypeError действие не подходит к типу: вызов не-функции, .name у null
RangeError значение вне допустимого диапазона

try … catch

try {
  console.log("пробуем");
  const user = null;
  console.log(user.name);
  console.log("сюда не дойдём");
} catch (error) {
  console.log("Поймали:", error.name, "-", error.message);
}
console.log("программа работает дальше");

Вывод:

пробуем
Поймали: TypeError - Cannot read properties of null (reading 'name')
программа работает дальше

Код в try выполняется как обычно. Если в нём случилась ошибка, выполнение сразу перепрыгивает в catch, а в переменную error попадает объект ошибки. У него есть name (вид) и message (текст). Если ошибки не было, catch пропускается.

Если объект ошибки не нужен, скобки можно не писать: catch { … }.

finally

Блок finally выполняется всегда — была ошибка или нет. Туда кладут «уборку»: закрыть файл, спрятать индикатор загрузки.

try {
  console.log("загружаем...");
} catch (e) {
  console.log("ошибка");
} finally {
  console.log("прячем спиннер");
}

Вывод:

загружаем...
прячем спиннер

throw — выбросить свою ошибку

Свои функции тоже могут сообщать о проблеме, «выбрасывая» ошибку:

function buy(price, money) {
  if (price > money) {
    throw new Error("Недостаточно денег");
  }
  return money - price;
}

try {
  console.log(buy(50, 100));
  console.log(buy(500, 100));
} catch (e) {
  console.log("Ошибка:", e.message);
}

Вывод:

50
Ошибка: Недостаточно денег

throw прерывает функцию, как return, но вместо результата «летит» ошибка — до ближайшего catch выше по цепочке вызовов. Выбрасывать можно и конкретный вид: new TypeError(…), new RangeError(…).

Ловить только свои ошибки

Иногда нужно обработать один вид ошибки, а остальные пропустить дальше:

try {
  doSomething();
} catch (e) {
  if (e instanceof RangeError) {
    console.log("исправим");
  } else {
    throw e;   // не наша — пробрасываем
  }
}

Ловить «всё подряд» и молча игнорировать — плохая привычка: настоящие баги будут прятаться.

JSON

JSON (JavaScript Object Notation) — текстовый формат, похожий на объекты JS:

{
  "name": "Аня",
  "age": 15,
  "skills": ["html", "css"],
  "admin": false,
  "pet": null
}

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

Объект → строка JSON: JSON.stringify

const user = { name: "Аня", age: 15, hobbies: ["рисование"] };
const text = JSON.stringify(user);
console.log(text);
console.log(typeof text);

Вывод:

{"name":"Аня","age":15,"hobbies":["рисование"]}
string

JSON.stringify(obj, null, 2) — красивый вывод с отступами в 2 пробела.

Строка JSON → объект: JSON.parse

const data = JSON.parse('{"title": "Курс JS", "lessons": 16}');
console.log(data.lessons + 1);

Вывод:

17

Если строка — не правильный JSON, JSON.parse выбрасывает SyntaxError:

try {
  JSON.parse("{name: 'Аня'}");   // ключ без кавычек, одинарные кавычки
} catch (e) {
  console.log(e.name);
}

Вывод:

SyntaxError

Пара JSON.parse(JSON.stringify(obj)) — старый способ сделать глубокую копию простого объекта.

Как это работает внутри

Когда выбрасывается ошибка, движок «разматывает» стек вызовов: выходит из текущей функции, потом из той, что её вызвала, и так далее, пока не найдёт try с catch. Если не найдёт — программа останавливается, и ошибка печатается в консоль. Поэтому catch можно поставить не прямо вокруг опасной строки, а там, где ты знаешь, что делать с ошибкой.

У объекта ошибки есть ещё свойство stack — список функций, через которые «пролетела» ошибка. Он очень помогает найти место поломки.

Частые ошибки

  1. throw "текст" вместо throw new Error("текст"). Строка не имеет name, message и stack. Всегда выбрасывай объект ошибки.
  2. Пустой catch. catch {} молча проглатывает любые проблемы — баги станет невозможно найти.
  3. try вокруг асинхронного кода. Ошибку внутри колбэка setTimeout такой try не поймает.
  4. Одинарные кавычки в JSON. JSON.parse("{'a': 1}") → SyntaxError. В JSON только двойные.
  5. Забыли, что stringify возвращает строку. JSON.stringify(obj).name — undefined.

Шпаргалка

Что Как
Поймать ошибку try { … } catch (e) { … }
Всегда выполнить finally { … }
Выбросить throw new Error("текст")
Конкретный вид new TypeError(…), new RangeError(…)
Проверить вид e instanceof RangeError
Текст и вид e.message, e.name
Пробросить дальше throw e;
В JSON-строку JSON.stringify(obj)
Из JSON-строки JSON.parse(text)

Безопасный разбор

Лёгкая+10 XP

Напиши функцию safeParse(text): если text — правильный JSON, вернуть разобранное значение, а если нет — вернуть null (программа не должна падать).

safeParse('{"a": 1}')   → { a: 1 }
safeParse("[1, 2]")     → [1, 2]
safeParse("{oops}")     → null

Подключи коннектор, чтобы решать задачи

Код задач выполняется на твоём компьютере — так быстрее и надёжнее, чем в браузере. Для этого нужна бесплатная программа-коннектор CodeWithMe. Подключить её нужно один раз.

Ищем коннектор на этом компьютере…

  1. 1
    Скачай коннектор для своей системы (Windows, macOS или Linux).Скачать коннекторНа странице загрузки выбери файл со своей системой в названии, например windows-amd64.
  2. 2Запусти его и выбери папку, где будут лежать твои решения. Python и Node.js он поставит туда сам, когда понадобится.
  3. 3
    Введи ниже код из 6 цифр — он написан в окне коннектора («Код для сайта CodeWithMe»). Если браузер спросит про доступ к локальной сети — разреши.

Коннектор открытый (исходный код на GitHub), работает только на твоём компьютере и выполняет код лишь после ввода кода сопряжения.