← Назад к вопросам
Как работает JSON.stringify со вложенными объектами?
1.3 Junior🔥 151 комментариев
#JavaScript Core#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает JSON.stringify со вложенными объектами
JSON.stringify() рекурсивно преобразует объекты и массивы в JSON-строку. Процесс обхода идёт глубоко вниз по всем вложенным уровням, пока не встретит примитивы или специальные значения.
Базовый пример с вложенными объектами
const user = {
name: 'John',
age: 30,
address: {
city: 'New York',
country: 'USA',
coordinates: {
lat: 40.7128,
lng: -74.0060
}
},
hobbies: ['reading', 'coding', 'gaming']
};
const json = JSON.stringify(user);
console.log(json);
// {"name":"John","age":30,"address":{"city":"New York","country":"USA","coordinates":{"lat":40.7128,"lng":-74.0060}},"hobbies":["reading","coding","gaming"]}
Форматирование с отступами
const json = JSON.stringify(user, null, 2);
console.log(json);
// {
// "name": "John",
// "age": 30,
// "address": {
// "city": "New York",
// "country": "USA",
// "coordinates": {
// "lat": 40.7128,
// "lng": -74.006
// }
// },
// "hobbies": ["reading", "coding", "gaming"]
// }
Как обрабатываются разные типы значений
const data = {
string: 'hello',
number: 42,
boolean: true,
null: null,
undefined: undefined, // undefined будет пропущен!
symbol: Symbol('test'), // Symbol будет пропущен!
function: () => {}, // функции пропускаются
date: new Date(),
array: [1, 2, 3],
nested: {
deep: {
value: 'found'
}
}
};
const json = JSON.stringify(data);
console.log(json);
// {"string":"hello","number":42,"boolean":true,"null":null,"date":"2024-01-15T10:30:00.000Z","array":[1,2,3],"nested":{"deep":{"value":"found"}}}
// undefined, symbol, function были исключены!
// Date преобразовалась в строку через toJSON()
Использование replacer функции
// replacer - это функция (value, key) => newValue
const user = {
name: 'John',
password: 'secret123',
email: 'john@example.com',
profile: {
bio: 'Developer',
apiKey: 'secret-key-123'
}
};
// Фильтруем конфиденциальные поля
const json = JSON.stringify(user, (key, value) => {
if (key === 'password' || key === 'apiKey') {
return undefined; // исключаем из JSON
}
return value;
});
console.log(json);
// {"name":"John","email":"john@example.com","profile":{"bio":"Developer"}}
Использование replacer массива
const user = {
id: 1,
name: 'John',
password: 'secret',
email: 'john@example.com',
age: 30
};
// replacer массив - список ключей которые должны быть включены
const json = JSON.stringify(user, ['id', 'name', 'email']);
console.log(json);
// {"id":1,"name":"John","email":"john@example.com"}
Использование toJSON метода
class User {
constructor(name, password) {
this.name = name;
this.password = password;
this.email = name.toLowerCase() + '@example.com';
}
toJSON() {
// Контролируем что попадёт в JSON
return {
name: this.name,
email: this.email
// password исключён!
};
}
}
const user = new User('John', 'secret123');
const json = JSON.stringify(user);
console.log(json);
// {"name":"John","email":"john@example.com"}
Циклические ссылки (типичная ошибка)
// ОШИБКА: TypeError - циклические структуры
const obj = { a: 1 };
obj.self = obj; // циклическая ссылка
JSON.stringify(obj); // TypeError: Converting circular structure to JSON
// РЕШЕНИЕ: Используем WeakSet для отслеживания
function stringifyWithCircular(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return '[Circular]';
}
seen.add(value);
}
return value;
});
}
const obj = { a: 1 };
obj.self = obj;
const json = stringifyWithCircular(obj);
console.log(json);
// {"a":1,"self":"[Circular]"}
Порядок обхода объектов
const data = {
numbers: [1, 2, 3],
nested: {
inner: {
value: 42,
array: ['a', 'b']
},
flat: 'value'
},
name: 'test'
};
const json = JSON.stringify(data, (key, value) => {
console.log(`Processing key: "${key}"`);
return value;
});
// Output:
// Processing key: ""
// Processing key: "numbers"
// Processing key: "0"
// Processing key: "1"
// Processing key: "2"
// Processing key: "nested"
// Processing key: "inner"
// Processing key: "value"
// Processing key: "array"
// Processing key: "0"
// Processing key: "1"
// Processing key: "flat"
// Processing key: "name"
Производительность со вложенными объектами
// Большой вложенный объект
const bigData = {
level1: {
level2: {
level3: {
// ... много уровней
data: Array(1000).fill(0).map((_, i) => ({ id: i }))
}
}
}
};
// Без контроля - может быть медленно
const json = JSON.stringify(bigData);
// С оптимизацией - только нужные поля
const json = JSON.stringify(bigData, (key, value) => {
if (Array.isArray(value) && value.length > 100) {
return value.slice(0, 10); // ограничиваем размер
}
return value;
});
Важные моменты
- undefined, Symbol, функции пропускаются на уровне объектов
- В массивах undefined становится null
- Date преобразуется в ISO-строку через toJSON()
- Циклические ссылки вызывают ошибку
- Большие объекты могут быть медленными
- Используй toJSON() для контроля сериализации
- replacer позволяет фильтровать или трансформировать данные
JSON.stringify со вложенными объектами - это мощный инструмент, но требует понимания как он обрабатывает разные типы данных и циклические ссылки.