如何在JS中获取数组对象的特定属性?

4

我有以下代码和测试数据:

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) => {
        return (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj;
    });
}

const obj = 
 [
  {
      a: 1,
      c: [
        {
          d: 1,
          e: 'string',
          f: [
            {
              value: 0,
            },
            {
              value: 1,
            }
          ],
        },
      ],
  },
    {
      a: 2,
      c: [
        {
          d: 2,
          e: 'string',
          f: [
            {
              value: 3,
            },
            {
              value: 4,
            }
          ],
        },
      ],
  },
 ];

console.log(obj);
const fs = obj.map(o => getNestedObject(o, ['c', 'f']));
console.log(fs);

我想要做的是,给定下面显示的对象数组,我想从每个对象中仅获取名为f的属性。因此,最终结果应该是每个对象的f值的数组。由于'f'是一个数组,我希望最终结果是一个只包含所有'f'属性元素的数组,类似于这些'f'被展开成一个数组。我的上面的getNestedObject函数似乎不起作用,因为当下面的console.log语句返回整个对象时。有什么办法可以在JS中实现这一点吗?
所以基本上最终结果应该是:
[{ value: 0 }, { value: 1 }, { value: 3 }, {value: 4 }]

这在 JavaScript 中非常容易,但使用 lodash 可以一行代码解决 - 用 lodash 行吗? - danday74
@vlaz 在我的情况下,不存在具有相同属性名称的嵌套对象,并且 f 在我的情况下始终是一个数组,但是为了论证起见,我们应该只获取 f 的第一次出现。 - tinker
@danday74 不,我不想使用任何外部包。感谢您指出这一点。一个纯JS的解决方案将是受欢迎的。但当然,为了完整起见,您也可以包括它。 - tinker
@ibrahimmahrir 是的,没错。 - tinker
这可能不是一个很好的白板练习,哈哈 - zebnat
显示剩余4条评论
4个回答

4
您可以将reduce()map()结合使用。基本上,将主数组缩减为所有c.f项的展平数组。这会检查c属性,以防对象没有该属性:

const obj = [{a: 1,c: [{d: 1,e: 'string',f: [{value: 0,},{value: 1,}],},],},{a: 2,c: [{d: 2,e: 'string',f: [{value: 3,},{value: 4,}],},],},];

let Fs = obj.reduce((arr, item) => 
    item.c
    ? arr.concat(...item.c.map(itemc => itemc.f ))  // concat for flattened rather than nested arrays
    : arr
    , []);

console.log(Fs)


谢谢。这似乎很好用。有一件事是我需要在最后将数组展平。我对你的答案进行了编辑,以达到我想要的效果。 - tinker
1
感谢@tinker。您可以使用...扩展运算符在concat调用中将整个内容压平。我已经编辑了答案以进行演示。 - Mark

1
这是一个快速迭代的解决方案,不会溢出堆栈,不假设目标结果值为数组(只有在目标结果为数组时才使用展开操作符),也不会硬编码子键名(它将探索任何是数组的值)。
如果目标具有与您想要包含在搜索中的键匹配的子项,则此方法也适用(将else if替换为if)。

const get = (data, target) => {
  const result = [];
  const stack = [data];
  
  while (stack.length) {
    const curr = stack.pop();
    
    for (const o of curr) {
      for (const k in o) {
        if (k === target) {
          if (Array.isArray(o[k])) {
            result.push(...o[k]);
          }
          else {
            result.push(o[k]);
          }
        }
        else if (Array.isArray(o[k])) {
          stack.push(o[k]);
        }
      }
    }
  }
  
  return result;
};
 
const obj = 
[
  {
      a: 1,
      c: [
        {
          d: 1,
          e: 'string',
          f: [
            {
              value: 0,
            },
            {
              value: 1,
            }
          ],
        },
      ],
  },
    {
      a: 2,
      c: [
        {
          d: 2,
          e: 'string',
          f: [
            {
              value: 3,
            },
            {
              value: 4,
            }
          ],
        },
      ],
  },
 ];
 
 console.log(get(obj, "f"));


1
你可以递归遍历任何对象和数组以获取给定的属性。这适用于任何深度,并且不关心对象的结构:

const obj=[{a:1,c:[{d:1,e:"string",f:[{value:0},{value:1}]}]},{a:2,c:[{d:2,e:"string",f:[{value:3},{value:4}]}]}];

//curried function to grab a property by name off some object or array
function grab(prop) {
  //naming the inner function means it can be called recursively by name
  return function recursiveGrab(target) {
    if (Array.isArray(target)) {
      const arrayResult = target
          .filter(x => typeof x === "object") //remove non-objects (and non-arrays)
          .filter(Boolean) //remove null
          .map(recursiveGrab); //recursively call for the remaining objects 
      return flatten(arrayResult); //return a single dimensional array
    }
    
    //an object has the property - return it
    if (prop in target) {
      return target[prop];
    }
    
    //object doesn't have the property - check all values
    return recursiveGrab(Object.values(target));
  }
}

//small helper function. It's separated only to keep the logic for the traversal clear
function flatten(arr) {
  return arr.reduce((acc, curr) => acc.concat(curr), [])
}

const grabF = grab('f');

console.log(grabF(obj));


0

我没有注意到 f 总是在 c 内部。 我有一个递归且难看的解决方案,可以处理 f 在任何字段内的情况。

        const objArray = [
          {
              a: 1,
              c: [
                {
                  d: 1,
                  e: 'string',
                  f: [
                    {
                      value: 0,
                    },
                    {
                      value: 1,
                    }
                  ],
                },
              ],
             d: [
                {
                  d: 1,
                  e: 'string',
                  f: [
                    {
                      value: 'd',
                    },
                    {
                      value: 'd1',
                    }
                  ],
                },
              ],
          },
            {
              a: 2,
              c: [
                {
                  d: 2,
                  e: 'string',
                  f: [
                    {
                      value: 3,
                    },
                    {
                      value: 4,
                    }
                  ],
                },
              ],
              e: [
                {
                  d: 1,
                  e: 'string',
                  f: [
                    {
                      value: 'e',
                    },
                    {
                      value: 'e1',
                    }
                  ],
                },
              ],
            }
        ]
         
         
         const getFObject = (obj) => {
           let fObj = [];
           Object.keys(obj).some(key => {
             if (key === 'f') {
               fObj = obj[key];
               return true;
             }
             if (Array.isArray(obj[key])) {
               obj[key].forEach(nestedObj => {
                 fObj = fObj.concat(getFObject(nestedObj))
               });
             }
             return false;
           });
           return fObj;
         }
         
         const newArray = objArray.reduce((acc, obj) => {
           return acc.concat(getFObject(obj))
         }, []);
         console.log(newArray)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接