Введение в JSON и JavaScript
JSON (JavaScript Object Notation) — это легковесный формат обмена данными, который стал стандартом для взаимодействия между клиентом и сервером в веб-приложениях. Благодаря своей простоте и читаемости, JSON используется повсеместно: от конфигурационных файлов до API-запросов. В этой статье мы разберём, как работать с JSON в среде Node.js, освоим парсинг (преобразование строки в объект) и сериализацию (преобразование объекта в строку). Материал рассчитан на начинающих разработчиков, уже знакомых с основами JavaScript.
Что такое JSON и зачем он нужен?
JSON представляет собой текстовый формат, основанный на синтаксисе объектов JavaScript. Однако JSON — это просто строка, которую можно передавать по сети или хранить в файле. Основные типы данных в JSON:
- Строки (в двойных кавычках)
- Числа (целые и с плавающей точкой)
- Логические значения (true/false)
- null
- Массивы
- Объекты (ключи в двойных кавычках)
Пример валидной JSON-строки:
{
"name": "Анна",
"age": 28,
"isStudent": false,
"skills": ["JavaScript", "Node.js"],
"address": null
}
В отличие от обычного объекта JavaScript, JSON требует строгого синтаксиса: все ключи и строковые значения заключаются в двойные кавычки, а комментарии запрещены.
Парсинг JSON: JSON.parse()
Для преобразования JSON-строки в объект JavaScript используется метод JSON.parse(). Это необходимо, когда вы получаете данные от сервера, читаете файл или обрабатываете ввод пользователя.
Базовый пример парсинга
const jsonString = '{"name": "Иван", "age": 30}';
const user = JSON.parse(jsonString);
console.log(user.name); // Иван
console.log(user.age); // 30
Парсинг массива
const jsonArray = '[1, 2, "три", true]';
const arr = JSON.parse(jsonArray);
console.log(arr[2]); // три
Обработка ошибок парсинга
Невалидный JSON вызовет исключение SyntaxError. Всегда используйте try...catch при работе с ненадёжными данными:
try {
const invalid = '{"name": "Ошибка}';
const result = JSON.parse(invalid);
} catch (error) {
console.error('Ошибка парсинга:', error.message);
}
Также можно передать второй аргумент — функцию reviver, которая позволяет преобразовывать значения в процессе парсинга:
const json = '{"date": "2024-01-15", "count": "42"}';
const obj = JSON.parse(json, (key, value) => {
if (key === 'date') return new Date(value);
if (key === 'count') return Number(value);
return value;
});
console.log(obj.date.getFullYear()); // 2024
console.log(typeof obj.count); // number
Сериализация JSON: JSON.stringify()
Обратный процесс — преобразование объекта JavaScript в JSON-строку — выполняется с помощью JSON.stringify(). Это нужно для отправки данных на сервер, сохранения в файл или логирования.
Простой пример сериализации
const user = {
name: 'Мария',
age: 25,
isAdmin: true
};
const json = JSON.stringify(user);
console.log(json);
// {"name":"Мария","age":25,"isAdmin":true}
Форматирование вывода
Метод принимает три параметра: значение, заменяющую функцию (или массив полей) и количество пробелов для отступов:
const data = {
id: 1,
title: 'Статья',
tags: ['js', 'json']
};
// С отступами в 2 пробела
const prettyJson = JSON.stringify(data, null, 2);
console.log(prettyJson);
/* Вывод:
{
"id": 1,
"title": "Статья",
"tags": [
"js",
"json"
]
}
*/
Фильтрация полей
Второй параметр может быть массивом ключей, которые нужно включить в результат:
const user = {
name: 'Петр',
password: 'secret123',
email: 'petr@example.com',
role: 'admin'
};
const safeJson = JSON.stringify(user, ['name', 'email']);
console.log(safeJson);
// {"name":"Петр","email":"petr@example.com"}
Проблемы с циклическими ссылками
Если объект содержит ссылки сам на себя, JSON.stringify() выбросит ошибку:
const obj = {};
obj.self = obj;
try {
JSON.stringify(obj);
} catch (error) {
console.error('Циклическая ссылка:', error.message);
}
Для решения можно использовать библиотеки или собственную заменяющую функцию, которая отслеживает уже обработанные объекты.
Практический пример: чтение и запись JSON-файла в Node.js
Рассмотрим полный цикл работы с JSON в Node.js: чтение из файла, модификация данных и запись обратно.
Чтение JSON-файла
const fs = require('fs');
try {
const rawData = fs.readFileSync('data.json', 'utf8');
const data = JSON.parse(rawData);
console.log('Загружено:', data);
} catch (error) {
console.error('Ошибка чтения файла:', error.message);
}
Запись JSON-файла
const config = {
port: 3000,
host: 'localhost',
debug: true
};
const jsonConfig = JSON.stringify(config, null, 2);
fs.writeFileSync('config.json', jsonConfig, 'utf8');
console.log('Файл сохранён');
Полный пример: менеджер заметок
const fs = require('fs');
const path = 'notes.json';
// Инициализация файла, если его нет
if (!fs.existsSync(path)) {
fs.writeFileSync(path, '[]', 'utf8');
}
// Чтение заметок
function getNotes() {
const raw = fs.readFileSync(path, 'utf8');
return JSON.parse(raw);
}
// Добавление заметки
function addNote(text) {
const notes = getNotes();
notes.push({ id: Date.now(), text, createdAt: new Date().toISOString() });
fs.writeFileSync(path, JSON.stringify(notes, null, 2));
console.log('Заметка добавлена');
}
// Удаление заметки по id
function deleteNote(id