Сведение вложенного объекта JavaScript — очень распространенный вопрос, с которым я сталкивался в технических интервью.

Возьмем в качестве примера следующий объект input.

const input = {
  name: 'Mansi',
  age: 25,
  department: {
    name: 'Customer Experience',
    section: 'Technical',
    branch: {
       name: 'Bangalore',
       timezone: 'IST'
    }
  },
  company: {
   name: 'SAP',
   customers: ['Ford', 'Nestle']
  },
  skills: ['javascript', 'node.js', 'html']
}

Ожидаемый output может быть следующим:

const output = {
   name: 'Mansi',
   age: 25,
   department_name: 'Customer Experience',
   department_section: 'Technical',
   department_branch_name: 'Bangalore',
   department_branch_timezone: 'IST’,
   company_name: 'SAP',
   company_customers: ['Ford', 'Nestle'],
   skills: ['javascript', 'node.js', 'html']
}

Мы начнем с обсуждения наивных решений, а затем перейдем к окончательному решению, которое будет лучше с точки зрения пространственной и временной сложности.

Мы будем использовать два for .. in, чтобы написать решение следующим образом:

const flattenObject = (input) => {
 let result = {};
 for (const key in input) {
  if (!input.hasOwnProperty(key)) {
    continue;
  } 
  if (typeof input[key] === "object" &&!Array.isArray(input[key])) {
        var subFlatObject = flattenObject(input[key]);
        for (const subkey in subFlatObject) {
            result[key + "_" + subkey] = subFlatObject[subkey];
        }
    } else {
        result[key] = input[key];
    }
  }
  return result;
}

Другой подход может состоять в том, чтобы использовать Object.keys() и перебирать результат массива, как описано выше.

Чтобы повысить сложность кода, нам нужно сократить использование двух циклов for..in или отказаться от использования Object.keys(). Этого легко избежать, передав функции дополнительный параметр и используя ту же логику recursive. Дополнительный параметр будет использоваться для вычисления key для вложенных объектов.

const flattenObject = (input, keyName) => {
var result = {};
for (const key in input) {
 const newKey =  keyName ? `${keyName}_${key}` : key;
 if (typeof input[key] === "object" && !Array.isArray(input[key])) {
       result = {...result, ...flattenObject(input[key], newKey)}
 } else {
       result[newKey] = input[key];
 }
}
return result;
};

Рекурсия может быть очень полезной и эффективной, если ее правильно реализовать.