最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

json - Whats the best way to remove a property from nested javascript Object? - Stack Overflow

programmeradmin3浏览0评论

I have a tree object as below, I am trying to remove the items array property if it's empty. I am not sure on the best approach to do this?

I am thinking of looping through the key, check the property and then remove using delete myJSONObject[prop]... Any thoughts / ideas are wele?

[{
    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: []
                    }]
                }]
            }]
        }]
    }]
}]

I have a tree object as below, I am trying to remove the items array property if it's empty. I am not sure on the best approach to do this?

I am thinking of looping through the key, check the property and then remove using delete myJSONObject[prop]... Any thoughts / ideas are wele?

[{
    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: []
                    }]
                }]
            }]
        }]
    }]
}]
Share Improve this question edited Jan 15, 2013 at 18:37 Learner asked Jan 15, 2013 at 18:26 LearnerLearner 2,33910 gold badges46 silver badges83 bronze badges 3
  • I would build a new object, rather than trying to modify this one. – Alex Wayne Commented Jan 15, 2013 at 18:39
  • Hey, you solved this yet? – Gideon Commented Jul 8, 2015 at 9:02
  • stackoverflow./questions/9446426/… – J4S0Nc Commented Aug 29, 2015 at 10:42
Add a ment  | 

5 Answers 5

Reset to default 5

This should do the job (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

Same in 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

You can have recursive algorithm that at each step either removes items array and returns, or recursively processes each individual object of the array.

I would also try to do this on the server-side. It will save a lot of plexity, memory, and processing time. There are usually ways of "excluding" empty arrays from the JSON encoded string.

Here is a solution using 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/[email protected]"></script>

Disclaimer: I'm the author of object-scan

This old question has been brought back up, and I think modern JS works well with recursion to yield a simple answer to do this in an immutable way:

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}

This function simply maps over the array, keeping the rest of each object, and for its items property, skipping it when it's empty and recurring when it's not.

I've got to say, when the question was first asked, this answer would have looked quite foreign! Now it's just normal JS!

This is my (probably not perfect) TypeScript with Generics solution.

It tries to infer first level keyof - maybe some more advanced Guru may help :)

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>;
}
发布评论

评论列表(0)

  1. 暂无评论