如何从任意层级的嵌套JavaScript对象中删除属性?

12

假设我有嵌套的对象,例如:

var obj = {
    "items":[
        {
            "name":"Item 1", 
            "value": "500",
            "options": [{...},{...}]
        },
        {
            "name":"Item 2", 
            "value": "300",
            "options": [{...},{...}]
        }
    ],
    "name": "Category",
    "options": [{...},{...}]
};

我希望从所有对象的任何深度中删除options属性。对象可以嵌套在对象和数组中。

我们目前正在项目中使用Lodash,但我对任何解决方案都很感兴趣。


也许这个可以帮助 https://github.com/jonschlinkert/omit-deep - karlkurzer
8个回答

9

没有一种直接的方法可以实现这一点,但是您可以使用以下函数从JSON中删除一个键。

function filterObject(obj, key) {
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            filterObject(obj[i], key);
        } else if (i == key) {
            delete obj[key];
        }
    }
    return obj;
}

并像这样使用它

var newObject = filterObject(old_json, "option");

3
哦,我们的代码库是在严格模式下运行的,我遇到了以下错误:Uncaught SyntaxError:Delete of an unqualified identifier in strict mode。 - orszaczky
@void 有没有不用递归的方法来实现这个,我即使使用了这里发布的类似解决方案 https://softwareengineering.stackexchange.com/a/323670 ,仍然会得到“RangeError: Maximum call stack size exceeded”的错误。 - erotavlas
@erotavlas,也许你只需要传递对象的一部分而不是整个对象。这将减少迭代次数。 - void
1
似乎应该是删除 obj[key] 而不是删除键。 - Justin Caldicott
如果键包含对象作为值,则@sboyd在此处提供的解决方案(https://dev59.com/t1sW5IYBdhLWcg3wwZjG#62564765)更为结构化。 - kamran

6
修改上面的解决方案,以删除我的 JSON 中多次出现的"dataID"。下面的代码可以正常工作。

var candidate = {
  "__dataID__": "Y2FuZGlkYXRlOjkuOTI3NDE5MDExMDU0Mjc2",
  "identity": {
    "__dataID__": "aWRlbnRpdHk6NjRmcDR2cnhneGE3NGNoZA==",
    "name": "Sumanth Suvarnas"
  },  
};

candidate = removeProp(candidate, "__dataID__")

console.log(JSON.stringify(candidate, undefined, 2));

function removeProp(obj, propToDelete) {
   for (var property in obj) {
      if (typeof obj[property] == "object") {
         delete obj.property
         let newJsonData= this.removeProp(obj[property], propToDelete);
         obj[property]= newJsonData
      } else {
          if (property === propToDelete) {
            delete obj[property];
          }
        }
    }
    return obj
}


delete obj.property 是一个打字错误吗? - Vitim.us

5
对Void的答案进行一点修改,使其可以删除属性,这些属性也是对象。
function filterObject(obj, key) {
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (i == key) {
            delete obj[key];
        } else if (typeof obj[i] == 'object') {
            filterObject(obj[i], key);
        }
    }
    return obj;
}

3
现在我们使用 object-scan 来处理像这样的数据处理任务。一旦你理解了它,它就非常强大。以下是如何回答你的问题。

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

const prune = (input) => objectScan(['**.options'], {
  rtn: 'count',
  filterFn: ({ parent, property }) => {
    delete parent[property];
  }
})(input);

const obj = { items: [{ name: 'Item 1', value: '500', options: [{}, {}] }, { name: 'Item 2', value: '300', options: [{}, {}] }], name: 'Category', options: [{}, {}] };

console.log(prune(obj));
// => 3

console.log(obj);
// => { items: [ { name: 'Item 1', value: '500' }, { name: 'Item 2', value: '300' } ], name: 'Category' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

声明: 我是object-scan的作者。


2
我有类似的问题。因此,我开发了以下库。请查看 GitHub 上该库的源代码,并可以使用 npm 下载。
您可以按照以下方式使用函数 removePropertiesDeeplyisInitialized 来删除所有未初始化的属性(如空对象、空数组、空字符串或非有限数字)。
const {removePropertiesDeeply, isInitialized} = require("@thedolphinos/utility4js");

const object = {
  a: null,
  b: "",
  x: {
    a: null,
    b: ""
  },
  y: [],
  z: [
    null,
    "",
    {a: null, b: ""},
    [[{a: {b: null, c: ""}}]],
    "abc"
  ]
};

removePropertiesDeeply(object, (x) => !isInitialized(x));
console.log(JSON.stringify(object)); // See that the object becomes {"z":["abc"]}.

1
function omit(source) {
  return isArray(source)
    ? source.map(omit)
    : isObject(source)
    ? (({ options, ...rst }) => mapValues(rst, omit))(source)
    : source;
}

与lodash一样,这很容易,你也可以通过参数指定键,例如:
function omit(source, omitKey) {
  return isArray(source)
    ? source.map(partialRight(omit,omitKey)))
    : isObject(source)
    ? (({[omitKey]: _, ...rst }) => mapValues(rst, partialRight(omit,omitKey)))(source)
    : source;
}

1
我曾经遇到了类似的问题并解决了它。我希望我的解决方案能对某些人有所帮助。
我使用Es6的...扩展运算符对对象进行浅拷贝,并将我不感兴趣的属性设置为null。
const newObject = {
   ...obj.items,
   ...obj.name,
   options: null // option property will be null.
}

“undefined” 更准确,因为您正在删除信息。 - jorisw
这对于问题中的“任何级别”部分不起作用。你提到它是浅层的,但那不是问题。 - cmfolio

1
您可以使用以下函数根据条件删除属性:
// Warning: this function mutates original object
const removeProperties = (obj, condition = (key, value) => false) => {
  for (var key in obj) {
    const value = obj[key]
    if (!obj.hasOwnProperty(key)) continue
    if (typeof obj[key] === "object") {
      removeProperties(obj[key], condition)
    } else if (condition(key, value)) {
      delete obj[key]
    }
  }
  return obj
}

示例:

// Remove all properties where key is equal to 'options'
removeProperties(someObject, (key, value) => key === 'options'))


// Remove all properties where key starts with 'ignore_'
removeProperties(someObject, (key, value) => key.startsWith('ignore_'))


// Remove all properties where value is null
removeProperties(someObject, (key, value) => value === null))

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