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

Развертывание вложенного объекта в плоскую структуру

2.0 Middle🔥 191 комментариев
#JavaScript Core#Архитектура и паттерны

Условие

Напишите функцию flattenObject(obj), которая преобразует вложенный объект в плоскую структуру с точечной нотацией ключей.

Требования

  1. Функция должна рекурсивно обходить все вложенные объекты
  2. Ключи в результате должны быть соединены через точку
  3. Массивы обрабатывать с числовыми индексами в ключах

Примеры

flattenObject({
  a: {
    b: 1,
    c: {
      d: 2
    }
  },
  e: 3
});
// Результат: { "a.b": 1, "a.c.d": 2, "e": 3 }

flattenObject({
  user: {
    name: "John",
    address: {
      city: "Moscow"
    }
  }
});
// Результат: { "user.name": "John", "user.address.city": "Moscow" }

Бонус

Реализуйте обратную функцию unflattenObject, которая восстанавливает вложенную структуру.

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение: Развертывание вложенного объекта в плоскую структуру

Задача и её применение

Развёртывание вложенных объектов часто требуется при работе с конфигурациями, сохранением в базы данных, экспортом в CSV и прочих сценариях, где нужна плоская структура данных. Эта функция использует рекурсию для обхода всех уровней вложенности.

Базовое решение

function flattenObject(obj, prefix = '') {
  const result = {};
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const value = obj[key];
      const newKey = prefix ? `${prefix}.${key}` : key;
      
      if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
        Object.assign(result, flattenObject(value, newKey));
      } else {
        result[newKey] = value;
      }
    }
  }
  
  return result;
}

Версия с поддержкой массивов

function flattenObject(obj, prefix = '') {
  const result = {};
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const value = obj[key];
      const newKey = prefix ? `${prefix}.${key}` : key;
      
      if (Array.isArray(value)) {
        value.forEach((item, index) => {
          const arrayKey = `${newKey}[${index}]`;
          
          if (item !== null && typeof item === 'object' && !Array.isArray(item)) {
            Object.assign(result, flattenObject(item, arrayKey));
          } else {
            result[arrayKey] = item;
          }
        });
      } else if (value !== null && typeof value === 'object') {
        Object.assign(result, flattenObject(value, newKey));
      } else {
        result[newKey] = value;
      }
    }
  }
  
  return result;
}

TypeScript версия

type FlatObject = Record<string, any>;

function flattenObject(
  obj: Record<string, any>,
  prefix: string = ''
): FlatObject {
  const result: FlatObject = {};
  
  Object.entries(obj).forEach(([key, value]) => {
    const newKey = prefix ? `${prefix}.${key}` : key;
    
    if (
      value !== null &&
      typeof value === 'object' &&
      !Array.isArray(value)
    ) {
      Object.assign(result, flattenObject(value, newKey));
    } else {
      result[newKey] = value;
    }
  });
  
  return result;
}

Обратная функция - unflattenObject

function unflattenObject(obj) {
  const result = {};
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const value = obj[key];
      const keys = key.split('.');
      
      let current = result;
      for (let i = 0; i < keys.length - 1; i++) {
        const k = keys[i];
        if (!(k in current)) {
          current[k] = {};
        }
        current = current[k];
      }
      
      current[keys[keys.length - 1]] = value;
    }
  }
  
  return result;
}

Примеры использования

const nested = {
  a: {
    b: 1,
    c: {
      d: 2
    }
  },
  e: 3
};

const flattened = flattenObject(nested);
console.log(flattened);
// { "a.b": 1, "a.c.d": 2, "e": 3 }

const user = {
  user: {
    name: "John",
    address: {
      city: "Moscow",
      zip: "101000"
    }
  }
};

const flat = flattenObject(user);
console.log(flat);
// Результат с развёрнутыми ключами

const flattedData = { "a.b": 1, "a.c.d": 2, "e": 3 };
const unflattened = unflattenObject(flattedData);
console.log(unflattened);
// Восстановленная структура

Версия с параметрами сепаратора

function flattenObject(obj, prefix = '', separator = '.') {
  const result = {};
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const value = obj[key];
      const newKey = prefix ? `${prefix}${separator}${key}` : key;
      
      if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
        Object.assign(result, flattenObject(value, newKey, separator));
      } else {
        result[newKey] = value;
      }
    }
  }
  
  return result;
}

Реальные применения

  • MongoDB: сохранение вложенных данных в плоском формате
  • CSV экспорт: преобразование объектов в табличный формат
  • Конфигурации: хранение вложенных параметров с точечной нотацией
  • Кэширование: индексирование вложенных значений

Ключевые моменты

  • Рекурсия: глубокий обход всех уровней
  • hasOwnProperty: исключает наследованные свойства
  • Null check: null является объектом в JavaScript
  • Array check: массивы должны обрабатываться отдельно
  • Object.assign: объединяет результаты рекурсивных вызовов