Объекты и JSON кажутся простыми, но именно здесь часто появляются ошибки, которые выглядят как “что-то не то в логике”. Ниже - самые типовые проблемы и понятные способы их избегать.
1) Отсутствующее свойство и undefined
Если свойства нет, чтение вернет undefined.
const user = { name: "Sam" };
console.log(user.email); // undefined
Проблема начинается, когда undefined используется дальше как объект или строка.
const user = { name: "Sam" };
try {
console.log(user.email.toLowerCase());
} catch (e) {
console.log(e.name); // "TypeError"
}
Практичный подход - проверка или безопасный доступ:
const user = { name: "Sam" };
const email = user.email?.toLowerCase();
console.log(email); // undefined
2) Путаница точка vs квадратные скобки
Если ключ лежит в переменной, точка не работает.
const user = { name: "Sam" };
const key = "name";
console.log(user.key); // undefined
console.log(user[key]); // "Sam"
Скобки нужны также для ключей с дефисами и пробелами.
const obj = { "full name": "Sam Doe" };
console.log(obj["full name"]); // "Sam Doe"
3) Перепутан объект и массив
У массива индексы, у объекта ключи.
const users = [{ id: 1 }, { id: 2 }];
console.log(users[0].id); // 1
console.log(users.id); // undefined
const user = { id: 1, name: "Sam" };
console.log(user.id); // 1
console.log(user[0]); // undefined
Если структура данных не очевидна, помогает Array.isArray.
const value = [];
console.log(Array.isArray(value)); // true
4) Мутация через общую ссылку
“Сломалось само” обычно означает, что две переменные указывают на один объект.
const a = { n: 1 };
const b = a;
b.n = 99;
console.log(a.n); // 99
Чтобы не менять исходный объект, создается копия:
const a = { n: 1 };
const b = { ...a, n: 99 };
console.log(a.n); // 1
console.log(b.n); // 99
5) Поверхностная копия и вложенные объекты
Spread копирует только верхний уровень.
const a = { user: { name: "Sam" } };
const b = { ...a };
b.user.name = "Alex";
console.log(a.user.name); // "Alex"
Если нужно изменить вложенное поле без влияния на оригинал, копируется нужная ветка:
const a = { user: { name: "Sam" } };
const b = {
...a,
user: {
...a.user,
name: "Alex"
}
};
console.log(a.user.name); // "Sam"
console.log(b.user.name); // "Alex"
6) JSON.parse падает на невалидной строке
JSON.parse бросает SyntaxError, если строка не валидный JSON.
const input = '{ "a": 1, }';
try {
const data = JSON.parse(input);
console.log(data);
} catch (e) {
console.log(e.name); // "SyntaxError"
}
JSON не допускает запятые в конце и комментарии.
7) В JSON только двойные кавычки
Это валидный JavaScript-объект, но не JSON:
const obj = { a: 1 };
JSON-строка выглядит так:
const json = "{\"a\": 1}";
В JSON строки и ключи должны быть в двойных кавычках.
8) JSON.stringify “теряет” данные
undefined и функции в JSON не попадают.
const obj = { a: 1, b: undefined, c: () => 1 };
console.log(JSON.stringify(obj)); // {"a":1}
NaN и Infinity превращаются в null.
const obj = { n: NaN, i: Infinity };
console.log(JSON.stringify(obj)); // {"n":null,"i":null}
9) Циклические ссылки ломают stringify
const a = {};
a.self = a;
try {
JSON.stringify(a);
} catch (e) {
console.log(e.name); // "TypeError"
}
Это частая причина ошибки при попытке сериализовать “большой объект состояния”.
10) JSON копирование подходит не всегда
Иногда делают:
const copy = JSON.parse(JSON.stringify(obj));
Это работает только для простых данных. Теряются Date, undefined, функции, а циклические ссылки дают ошибку.
const data = { createdAt: new Date("2025-01-01T00:00:00Z") };
const copy = JSON.parse(JSON.stringify(data));
console.log(typeof copy.createdAt); // "string"
11) Проверка “есть ли ключ” через truthy/falsy
Если значение может быть 0, false или "", проверка через if (obj.key) может дать ложный результат.
const data = { retries: 0 };
if (data.retries) {
console.log("has retries");
} else {
console.log("no retries");
}
Более точная проверка:
const data = { retries: 0 };
console.log("retries" in data); // true
console.log(data.retries ?? 3); // 0
Что стоит запомнить
- Отсутствующее свойство дает
undefined, а цепочка чтения может привести к TypeError. - Для ключей в переменной нужны квадратные скобки.
- Объекты и массивы передаются по ссылке, случайные мутации встречаются часто.
- Spread делает поверхностную копию - для вложенности копируется нужная ветка.
- JSON строгий: только двойные кавычки, без комментариев и запятых в конце.
JSON.parseчасто требуетtry/catch,JSON.stringifyтеряет часть типов и не работает с циклами.