Сглаживание вложенных объектов со ссылкой на родительский объект - PullRequest
0 голосов
/ 12 ноября 2018

Я хотел бы свести ниже

let o = {
  name: "John",
  school: {
    name: "Phillps",
  }
};

к:

{
  name: "John",
  schoolName: "Phillps"
}

Мой код выглядит следующим образом

f= Object.assign({}, ..._flatten(o));

function _flatten(o) {
  return [].concat(
    ...Object.keys(o).map(k =>
      typeof o[k] === "object" ? _flatten(o[k]) : { [k]: o[k] }
    )
  );
}

Это производит

{  
 name: "Phillps"
}

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

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Вы можете использовать Object.entries , Array.prototype.flatMap и Object.fromEntries

const upperFirst = (str = "") =>
  str[0] .toUpperCase () + str.substr(1)

const camelCase = ([ first = "", ...rest ]) =>
  first + rest .map (upperFirst) .join ('')

const append = (xs, x) =>
  xs .concat ([ x ])
  
const flatten = (o = {}) =>
{ const loop = (o, path) =>
    Object (o) === o
      ?  Object .entries (o) .flatMap
           ( ([ k, v ]) =>
               loop
                 ( v
                 , append (path, k)
                 )
           )
      : [ [ camelCase (path), o ] ]
  return Object .fromEntries (loop (o, []))
}

console.log
  ( flatten
      ( { name: "John"
        , school:
            { name: "Phillips"
            , district: { zone: 1 }
            }
        }
      )
  )
  
// { "name": "John"
// , "schoolName": "Phillips"
// , "schoolDistrictZone": 1
// }

flatMap охотно оценивает ввод и создает некоторые промежуточные значения, прежде чем flatten сможет вернуться. Поскольку Object.fromEntries принимает любую итерацию, нам, вероятно, лучше написать loop с генератором

const flatten = (o = {}) =>
{ const loop = function* (o, path)
  { if (Object (o) === o)
      for (const [ k, v ] of Object .entries (o))
        yield* loop
          ( v
          , append (path, k)
          )
    else
      yield [ camelCase (path), o ]
  }
  return Object .fromEntries (loop (o, []))
}

Перезапустите программу, и вы увидите точно такой же вывод. Также стоит упомянуть структурное сходство двух программ.

0 голосов
/ 12 ноября 2018

Вы можете использовать свой код и просто передать префикс в качестве аргумента _flatten(). Когда вы прибегаете к помощи, соедините префикс с текущим родительским ключом. Это продолжит добавлять префиксы, поскольку вложение становится глубже:

function _flatten(o, prefix="") {
  return [].concat(
    ...Object.keys(o).map(k =>
            typeof o[k] === "object" ? _flatten(o[k], prefix+k) : { [prefix+k]: o[k] }
    )
  );
}

let o = {
    name: "John",
    school: {
      name: "Phillps",
    }
  };

f= Object.assign({}, ..._flatten(o));

console.log(f)

Кроме того, вы можете просто немного кодировать, используя reduce() и Object.assign, вместо создания массивов с [].concact()

function _flatten(o, prefix = "") {
  return Object.keys(o).reduce((obj, k) =>
    Object.assign(obj, typeof o[k] === "object" 
        ? _flatten(o[k], prefix + k) 
        : { [prefix + k]: o[k]})
     , {})
}

let o = {
  name: "John",
  school: {
    name: "Phillps",
  }
};

f = _flatten(o);

console.log(f)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...