通过键数组访问对象的属性

时间:2018-10-10 10:32:31

标签: javascript algorithm ecmascript-6

我想编写一个辅助函数,以从对象数组中的每个对象中解压缩特定的对象属性。有时,此属性将是顶级的,而其他时候,它将嵌套任意数量的级别。因此,这个问题的症结在于:如何基于可变长度的键名数组访问对象属性?

我希望有这样的东西:

const func = (arrOfObjects, ...keys) {
    return arrOfObjects.map(object => {
        return object[keys[0]][keys[1]] ... [keys[N]];
    })
}

具有示例行为:

const input = [
    {a: b: {c: 10}},
    {a: b: {c: 11}},
    {a: b: {c: 12}}
]

console.log(func(input, 'a', 'b', 'c'))
// [10, 11, 12]
console.log(func(input, 'a', 'b'))
// [{c: 10}, {c: 11}, {c : 12}]

我觉得必须有一个不错的ES6向导解决方案,但尚未找到它,因此,任何帮助将不胜感激!

干杯

P

3 个答案:

答案 0 :(得分:1)

如果提供访问器,如[a, b, c[0], name],则可以编写一个自定义函数,如果在嵌套对象中找到该函数,则返回该值,否则返回未定义

 let obj = {
   a: 1,
   b: 2,
   c: {
     d: 1,
     e: [{
       f: 3,
       g: [{
         z: 45
       }]
     }]
   }
 }
function findKeyFromPattern(obj, patternArr) {
  let value = obj;
  for(let i = 0; i < patternArr.length; i++) {
    const arrmatch = patternArr[i].match(/(\w+)\[(\d+)\]/);
    if(arrmatch) { // pattern matches and array accessor syntax
      value = value[arrmatch[1]];
      if(typeof value === 'object' && value !== null) {
        value = value[arrmatch[2]];
      } else {
        return;
      }
    } else {
      if(value[patternArr[i]]) {
        value = value[patternArr[i]];
      } else {
        return;
      }
    }
  }
  return value;
}


console.log(findKeyFromPattern(obj, ['c', 'e[0]', 'g']));
console.log(findKeyFromPattern(obj, ['c', 'e[1]', 'g']))

答案 1 :(得分:1)

您可以使用Array#reduce

来获得简短的解决方案

const input = [
    {a: { b: {c: 10}}},
    {a: { b: {c: 11}}},
    {a: { b: {c: 12}}}
]


console.log(func(input, ['a', 'b', 'c']))
// [10, 11, 12]
console.log(func(input, ['a', 'b']))
// [{c: 10}, {c: 11}, {c : 12}]

function func(input, props) {
  return input.map(x => exctractByProps(x, props));
}

function exctractByProps(obj, props) {
  return props.reduce( 
    (acc, prop) => typeof acc === 'object' && prop in acc ? acc[prop] : undefined, 
    obj 
  )
}

主要逻辑是获取传入的所有属性,然后尝试获取与obj[prop[0]][prop[1]][prop[2]]/* ... */[prop[n]]相对应的值。如果对象的形状与prop不匹配(例如,输入{a: 1}, ['a', 'b']{d: {c: 1}}, ['a', 'b']),则函数返回undefined

答案 2 :(得分:1)

根据您给我的问题和示例给出的答案。似乎输入的顺序将始终与对象嵌套匹配。所以这是我的解决方案:

const func = (arrOfObjects, ...keys) => {
  return arrOfObjects.map(object => {
    let obj = object, integer = keys.length;
    for (let index = 0; index < integer; index++) {
      obj = obj[keys[index]];
      if(obj === undefined) break;
    }
    return obj;
  });
};

const input = [
  { a: { b: { c: 10 } } },
  { a: { b: { c: 11 } } },
  { a: { b: { c: 12 } } }
];

console.log(func(input, "a", "b", "c"));
// [10, 11, 12]
console.log(func(input, "a", "b"));
// [{c: 10}, {c: 11}, {c : 12}]

不幸的是,您所期望的并没有像JavaScript魔术这样的东西。 注意:当对象内的键的顺序以随机深度嵌套时,此代码将不起作用。但是对于您要解决的问题,这应该可以正常工作。另外,我尝试尽可能保留您的初始代码