从嵌套的javascript对象中删除属性的最佳方法是什么?

3yhwsihp  于 2023-03-11  发布在  Java
关注(0)|答案(5)|浏览(159)

我有一个树对象,如下所示,我试图删除项目数组属性,如果它是空的。我不知道最好的方法来做到这一点?
我正在考虑循环通过键,检查属性,然后使用delete myJSONObject[prop]删除...欢迎任何想法/想法?

[{
    text: "TreeRoot",
    items: [{
        text: "Subgroup1",
        items: []
    }, {
        text: "Subgroup2",
        items: []
    }, {
        text: "Subgroup3",
        items: [],
        items: [{
            text: "subgroup5",
            items: [{
                text: "subgroup6",
                items: [{
                    text: "subgroup7",
                    items: [{
                        text: "subgroup8",
                        items: []
                    }]
                }]
            }]
        }]
    }]
}]
mzaanser

mzaanser1#

这样就可以完成工作(ES5):

function removeEmpty(obj) {
  Object.keys(obj).forEach(function(key) {
    (key === 'items' && obj[key].length === 0) && delete obj[key] ||
    (obj[key] && typeof obj[key] === 'object') && removeEmpty(obj[key])
  });
  return obj;
};

JSBIN
ES6相同:

const removeEmpty = (obj) => {
  Object.keys(obj).forEach(key =>
    (key === 'items' && obj[key].length === 0) && delete obj[key] ||
    (obj[key] && typeof obj[key] === 'object') && removeEmpty(obj[key])
  );
  return obj;
};

JSBIN

watbbzwu

watbbzwu2#

您可以使用递归算法,在每一步删除items数组并返回,或者递归处理数组中的每个对象。
我也会尝试在服务器端这样做。这将保存大量的复杂性、内存和处理时间。通常有一些方法可以从JSON编码的字符串中“排除”空数组。

brccelvz

brccelvz3#

以下是使用object-scan的解决方案

// const objectScan = require('object-scan');

const data = [{ text: 'TreeRoot', items: [{ text: 'Subgroup1', items: [] }, { text: 'Subgroup2', items: [] }, { text: 'Subgroup3', items: [{ text: 'subgroup5', items: [{ text: 'subgroup6', items: [{ text: 'subgroup7', items: [{ text: 'subgroup8', items: [] }] }] }] }] }] }];

const modify = (obj) => objectScan(['**.items'], {
  rtn: 'count',
  filterFn: ({ value, parent, property }) => {
    if (Array.isArray(value) && value.length === 0) {
      delete parent[property];
      return true;
    }
    return false;
  }
})(obj);

console.log(modify(data)); // returns number of deletions
// => 3
console.log(data);
// => [ { text: 'TreeRoot', items: [ { text: 'Subgroup1' }, { text: 'Subgroup2' }, { text: 'Subgroup3', items: [ { text: 'subgroup5', items: [ { text: 'subgroup6', items: [ { text: 'subgroup7', items: [ { text: 'subgroup8' } ] } ] } ] } ] } ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.7.1"></script>
ao218c7q

ao218c7q4#

这个老问题又被提了出来,我认为现代JS可以很好地使用递归,以一种不可变的方式产生一个简单的答案:

const removeEmptyItems = (xs) =>
   xs .map (({items = [], ... rest}) => ({
    ... rest, 
    ... (items .length ? {items: removeEmptyItems(items)} : {})
  }))

const tree = [{text: "TreeRoot", items: [{text: "Subgroup1", items: []}, {text: "Subgroup2", items: []}, {text: "Subgroup3",items: [{text: "subgroup5", items: [{text: "subgroup6", items: [{text: "subgroup7", items: [{text: "subgroup8", items: []}]}]}]}]}]}]

console .log (removeEmptyItems (tree))
.as-console-wrapper {max-height: 100% !important; top: 0}

这个函数只是简单地Map数组,保留每个对象的其余部分,对于它的items属性,当它为空时跳过它,当它不为空时循环使用。
我不得不说,当这个问题第一次被问到的时候,这个答案看起来很洋气!现在它只是普通的JS!

mspsb9vt

mspsb9vt5#

这是我的(可能并不完美)TypeScript with泛型解决方案。
它试图推断第一级keyof -也许一些更高级的古鲁可能会有帮助:)

type MyObject = { [index: string]: unknown };

export function removeProperties<T extends MyObject, K extends keyof T>(obj: T, propsToRemove: K[]): Omit<T, K> {
  if (!obj) {
    return obj;
  }

  const newObj = { ...obj } as MyObject;
  Object.keys(newObj).forEach(key => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const value = obj[key] as any;

    if (propsToRemove.includes(key as K)) {
      delete newObj[key];
    } else if (typeof value === 'object' && value != null) {
      newObj[key] = removeProperties(value, propsToRemove);
    }
  });
  return newObj as Omit<T, K>;
}

相关问题