← Назад к вопросам

Как работает 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;
});

Важные моменты

  1. undefined, Symbol, функции пропускаются на уровне объектов
  2. В массивах undefined становится null
  3. Date преобразуется в ISO-строку через toJSON()
  4. Циклические ссылки вызывают ошибку
  5. Большие объекты могут быть медленными
  6. Используй toJSON() для контроля сериализации
  7. replacer позволяет фильтровать или трансформировать данные

JSON.stringify со вложенными объектами - это мощный инструмент, но требует понимания как он обрабатывает разные типы данных и циклические ссылки.