Json.parse та json.stringify в JavaScript
Що таке JSON?
JSON (JavaScript Object Notation) — текстовий формат для обміну даними, заснований на синтаксисі JavaScript.
JavaScript надає два основні методи для роботи з JSON:
JSON.stringify()— перетворення об'єкта в JSON-рядок (серіалізація)JSON.parse()— перетворення JSON-рядка в об'єкт (десеріалізація)
JSON.stringify()
Перетворює значення JavaScript в JSON-рядок.
Основний синтаксис
JSON.stringify(value, replacer, space)Параметри
value— значення для перетворенняreplacer(необов'язковий) — функція або масив для фільтрації властивостейspace(необов'язковий) — кількість пробілів для форматування
Простий приклад
const user = {
name: 'John',
age: 25,
isActive: true
};
JSON.stringify(user);
// '{"name":"John","age":25,"isActive":true}'
// З форматуванням
JSON.stringify(user, null, 2);
/*
{
"name": "John",
"age": 25,
"isActive": true
}
*/Що можна серіалізувати?
Підтримувані типи
// Об'єкти
JSON.stringify({ a: 1 }); // '{"a":1}'
// Масиви
JSON.stringify([1, 2, 3]); // '[1,2,3]'
// Рядки
JSON.stringify('text'); // '"text"'
// Числа
JSON.stringify(42); // '42'
// Логічні значення
JSON.stringify(true); // 'true'
// null
JSON.stringify(null); // 'null'Що ігнорується або перетворюється
const obj = {
fn: function() {}, // Функція - ігнорується
undef: undefined, // undefined - ігнорується
sym: Symbol('id'), // Symbol - ігнорується
date: new Date(), // Дата → рядок
nan: NaN, // NaN → null
infinity: Infinity, // Infinity → null
regex: /test/, // RegExp → {}
map: new Map([[1, 'one']]), // Map → {}
set: new Set([1, 2, 3]) // Set → {}
};
JSON.stringify(obj);
// '{"date":"2024-01-01T00:00:00.000Z","nan":null,"infinity":null,"regex":{},"map":{},"set":{}}'Важливо:
undefined, функції та символи:
- В об'єктах — ігноруються
- В масивах — стають
null
JSON.stringify([1, undefined, function() {}, 3]);
// '[1,null,null,3]'Параметр replacer
Масив (фільтрація властивостей)
const user = {
name: 'John',
age: 25,
password: 'secret123',
email: 'john@example.com'
};
// Серіалізувати лише ім'я та електронну пошту
JSON.stringify(user, ['name', 'email']);
// '{"name":"John","email":"john@example.com"}'Функція (перетворення значення)
const obj = {
name: 'John',
age: 25,
salary: 100000
};
JSON.stringify(obj, (key, value) => {
// Сховати зарплату
if (key === 'salary') return undefined;
// Подвоїти вік
if (key === 'age') return value * 2;
return value;
});
// '{"name":"John","age":50}'Параметри функції replacer
key— ключ пропси (порожній рядок для кореневого об'єкта)value— значення пропсиthis— батьківський об'єкт
const data = { a: 1, nested: { b: 2 } };
JSON.stringify(data, function(key, value) {
console.log(`key: "${key}", value:`, value);
return value;
});
// key: "", value: { a: 1, nested: { b: 2 } } ← кореневий об'єкт
// key: "a", value: 1
// key: "nested", value: { b: 2 }
// key: "b", value: 2Параметр space (форматування)
const obj = { name: 'John', age: 25 };
// Число - кількість пробілів
JSON.stringify(obj, null, 2);
/*
{
"name": "John",
"age": 25
}
*/
// Рядок - префікс для кожного рівня
JSON.stringify(obj, null, '→ ');
/*
{
→ "name": "John",
→ "age": 25
}
*/Метод toJSON()
Об'єкти можуть визначати власну поведінку серіалізації через метод toJSON().
const user = {
name: 'John',
birthDate: new Date(1998, 5, 15),
toJSON() {
return {
name: this.name,
age: new Date().getFullYear() - this.birthDate.getFullYear()
};
}
};
JSON.stringify(user);
// '{"name":"John","age":26}'Вбудований toJSON в Date
const date = new Date();
date.toJSON(); // "2024-01-15T12:00:00.000Z"
JSON.stringify({ created: date });
// '{"created":"2024-01-15T12:00:00.000Z"}'Циклічні посилання
const obj = { name: 'John' };
obj.self = obj; // Циклічне посилання
try {
JSON.stringify(obj);
} catch (error) {
console.error(error);
// TypeError: Converting circular structure to JSON
}Рішення: Використання WeakSet
function stringifyWithoutCircular(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 = { name: 'John' };
obj.self = obj;
stringifyWithoutCircular(obj);
// '{"name":"John","self":"[Circular]"}'JSON.parse()
Перетворює JSON-рядок в значення JavaScript.
Основний синтаксис
JSON.parse(text, reviver)Параметри
text— JSON-рядок для парсингуreviver(необов'язковий) — функція для перетворення значень
Приклади
JSON.parse('{"name":"John","age":25}');
// { name: 'John', age: 25 }
JSON.parse('[1, 2, 3]');
// [1, 2, 3]
JSON.parse('true'); // true
JSON.parse('null'); // null
JSON.parse('"text"'); // "text"
JSON.parse('42'); // 42Параметр reviver
Функція для перетворення значень під час парсингу.
const json = '{"name":"John","birthDate":"1998-06-15T00:00:00.000Z"}';
const user = JSON.parse(json, (key, value) => {
if (key === 'birthDate') {
return new Date(value); // Перетворити рядок в Date
}
return value;
});
console.log(user.birthDate instanceof Date); // trueПараметри функції reviver
key— ключ пропсиvalue— значення пропсиthis— батьківський об'єкт
Функція викликається знизу-вгору (від вкладених до кореневих).
const json = '{"a":1,"nested":{"b":2}}';
JSON.parse(json, (key, value) => {
console.log(`key: "${key}", value:`, value);
return value;
});
// key: "a", value: 1
// key: "b", value: 2
// key: "nested", value: { b: 2 }
// key: "", value: { a: 1, nested: { b: 2 } } ← останнійПомилки парсингу
// Синтаксична помилка
try {
JSON.parse("{name: 'John'}"); // Ключі повинні бути в лапках
} catch (error) {
console.error(error);
// SyntaxError: Unexpected token n in JSON at position 1
}
// Непарне закриття рядка
JSON.parse('{"name": "John}'); // SyntaxError
// Зайва кома
JSON.parse('{"a": 1,}'); // SyntaxError
// Дійсний JSON
JSON.parse('{"name":"John"}'); // OKJSON є більш строгим, ніж JavaScript:
- Ключі повинні бути в подвійних лапках
- Не можна використовувати зайві коми
- Тільки подвійні лапки для рядків
- Без коментарів
Глибоке клонування з JSON
Простий метод клонування
const original = {
name: 'John',
address: {
city: 'New York'
}
};
const clone = JSON.parse(JSON.stringify(original));
clone.address.city = 'Boston';
console.log(original.address.city); // 'New York'
console.log(clone.address.city); // 'Boston'Обмеження методу
const obj = {
date: new Date(),
fn: () => {},
undef: undefined,
map: new Map([[1, 'one']]),
set: new Set([1, 2])
};
const clone = JSON.parse(JSON.stringify(obj));
console.log(clone);
// { date: '2024-01-15T12:00:00.000Z' } ← Дата стала рядком
// fn, undef, map, set — втраченіПравильне глибоке клонування
Для повного клонування використовуйте structuredClone() (сучасний стандарт):
const original = {
date: new Date(),
map: new Map([[1, 'one']]),
set: new Set([1, 2])
};
const clone = structuredClone(original);
console.log(clone.date instanceof Date); // true
console.log(clone.map instanceof Map); // trueПрактичні приклади
LocalStorage
// Збереження
const user = { name: 'John', settings: { theme: 'dark' } };
localStorage.setItem('user', JSON.stringify(user));
// Завантаження
const loadedUser = JSON.parse(localStorage.getItem('user'));Запити до API
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John', age: 25 })
})
.then(response => response.json())
.then(data => console.log(data));Порівняння об'єктів
function deepEqual(obj1, obj2) {
return JSON.stringify(obj1) === JSON.stringify(obj2);
}
deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // true
deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 }); // false (порядок ключів має значення)Увага:
Цей метод працює лише для простих об'єктів і залежить від порядку ключів.
Продуктивність
const bigObject = { /* 10000 властивостей */ };
console.time('stringify');
const json = JSON.stringify(bigObject);
console.timeEnd('stringify'); // ~10ms
console.time('parse');
JSON.parse(json);
console.timeEnd('parse'); // ~5msJSON.parse()зазвичай швидший заJSON.stringify()- Може бути повільним для великих об'єктів
- Розгляньте потоки парсерів для величезного JSON
Висновок
JSON.stringify():
- Серіалізує об'єкти, масиви, примітиви
- Ігнорує функції, undefined, Symbol
- Підтримує
replacerдля фільтрації та перетворення - Підтримує
spaceдля форматування - Може бути налаштований через
toJSON() - Не працює з циклічними посиланнями
JSON.parse():
- Парсить дійсний JSON
- Підтримує
reviverдля перетворення - Більш строгий, ніж JavaScript (лапки, зайві коми)
- Може викидати
SyntaxError
Глибоке клонування через JSON:
- Простий метод
- Втрачає функції, Date, Map, Set
- Використовуйте
structuredClone()для повного клонування
На співбесідах:
Звичайні питання:
- Що втрачається з
JSON.stringify()? - Як обробити циклічні посилання?
- Яка різниця між
JSON.parse()таeval()? - Як зробити глибоке клонування?
- Що таке
replacerіreviver?
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.