使用 JavaScript 从对象中递归删除属性和值的最快方法是啥?

Posted

技术标签:

【中文标题】使用 JavaScript 从对象中递归删除属性和值的最快方法是啥?【英文标题】:Using JavaScript what's the quickest way to recursively remove properties and values from an object?使用 JavaScript 从对象中递归删除属性和值的最快方法是什么? 【发布时间】:2015-10-22 02:50:47 【问题描述】:

我需要找到从对象中删除所有$meta 属性及其值的最快方法,例如:


  "part_one": 
    "name": "My Name",
    "something": "123",
    "$meta": 
      "test": "test123"
    
  ,
  "part_two": [
    
      "name": "name",
      "dob": "dob",
      "$meta": 
        "something": "else",
        "and": "more"
      
    ,
    
      "name": "name",
      "dob": "dob"
    
  ],
  "$meta": 
    "one": 1,
    "two": 2
  

鉴于$meta 属性可能位于对象中的任何位置,因此应该变为以下形式,因此可能需要某种形式的递归。


  "part_one": 
    "name": "My Name",
    "something": "123"
  ,
  "part_two": [
    
      "name": "name",
      "dob": "dob"
    ,
    
      "name": "name",
      "dob": "dob"
    
  ]

任何帮助或建议将不胜感激!

谢谢!

【问题讨论】:

不要使用递归,而是制作对象的副本,省略您不想要的属性和值。关于 javascript 中递归的一般说明:它取决于浏览器的内存分配,这并不多,因此递归会占用大量资源,并且除非实施仔细的内存管理,否则不适用于大型数据集。 最快的方法是先自己实现,然后寻求帮助以使其更快。 您可以使用 for in 循环或更准确地说 for of --> developer.mozilla.org/en/docs/Web/JavaScript/Reference/… 来遍历对象的属性和值 【参考方案1】:

一个简单的自调用函数就可以做到。

function removeMeta(obj) 
  for(prop in obj) 
    if (prop === '$meta')
      delete obj[prop];
    else if (typeof obj[prop] === 'object')
      removeMeta(obj[prop]);
  

var myObj = 
  "part_one": 
    "name": "My Name",
    "something": "123",
    "$meta": 
      "test": "test123"
    
  ,
  "part_two": [
    
      "name": "name",
      "dob": "dob",
      "$meta": 
        "something": "else",
        "and": "more"
      
    ,
    
      "name": "name",
      "dob": "dob"
    
  ],
  "$meta": 
    "one": 1,
    "two": 2
  


function removeMeta(obj) 
  for(prop in obj) 
    if (prop === '$meta')
      delete obj[prop];
    else if (typeof obj[prop] === 'object')
      removeMeta(obj[prop]);
  


removeMeta(myObj);

console.log(myObj);

【讨论】:

直到 JS 有尾递归优化,这对于大对象来说是不安全的。对于具有循环引用的对象也是不安全的。 完美运行,如果您需要保留原始对象,请务必克隆对象。 我不认为它对我有用。如果那是一个对象,那么它只需要第一个属性。其他人呢?消除该特定道具后,它不会返回整个对象。或者我错过了什么?【参考方案2】:

正如@floor 上面评论的那样:

JSON.parse(JSON.stringify(obj, (k,v) => (k === '$meta')? undefined : v))

【讨论】:

相反,将替换器作为参数提供给 stringify 调用,从而避免将这些属性序列化为以开头的字符串 警告此方法将从对象中删除不可序列化的内容,例如函数或 DOM 元素【参考方案3】:

// Helper function
function removeProps(obj,keys)
  if(Array.isArray(obj))
    obj.forEach(function(item)
      removeProps(item,keys)
    );
  
  else if(typeof obj === 'object' && obj != null)
    Object.getOwnPropertyNames(obj).forEach(function(key)
      if(keys.indexOf(key) !== -1)delete obj[key];
      else removeProps(obj[key],keys);
    );
  

// The object we want to iterate
var obj = 
  "part_one": 
    "name": "My Name",
    "something": "123",
    "$meta": 
      "test": "test123"
    
  ,
  "part_two": [
    
      "name": "name",
      "dob": "dob",
      "$meta": 
        "something": "else",
        "and": "more"
      
    ,
    
      "name": "name",
      "dob": "dob"
    
  ],
  "$meta": 
    "one": 1,
    "two": 2
  
;
// Utilize the utility
removeProps(obj,['$meta']);
// Show the result
document.body.innerhtml = '<pre>' + JSON.stringify(obj,null,4) + '</pre>';

【讨论】:

在任何级别的纯 js 中实现这一点的聪明方法,谢谢!【参考方案4】:

我使用 @Joseph Marikle

的引用函数在对象中的any level 中的any key 中创建了这个函数
const _ = require("lodash");
const isObject = obj => obj != null && obj.constructor.name === "Object";
const removeAttrDeep = (obj, key) => 
    for (prop in obj) 
      if (prop === key) delete obj[prop];
      else if (_.isArray(obj[prop])) 
        obj[prop] = obj[prop].filter(k => 
          return !_.isEmpty(removeAttrDeep(k, key));
        );
      else if (isObject(obj[prop])) removeAttrDeep(obj[prop], key);
    
    return obj;
 ;

示例:

 const _obj = 
       a: "b", b: "e", c:  a: "a", b: "b", c: "c",
       d: [  a: "3" ,  b: ["2", "3"] ];
 console.log(removeAttrDeep(_obj, "b"));

【讨论】:

【参考方案5】:

(抱歉,我还没有足够的声望点来直接评论。)

仅供参考,typeof null === 'object',因此在@joseph-marikle 提供的 removeMeta() 示例中,该函数将在 null 值上递归。

在此处阅读更多信息:why is typeof null "object"?

【讨论】:

【参考方案6】:

这是一个函数,它需要一个字符串或一个字符串数组以递归方式删除(基于约瑟夫的回答):

// removes all propsToRemove (passed as an array or string), drilling down up to maxLevel times
// will modify the input and return it
du.removeAllPropsFromObj = function(obj, propsToRemove, maxLevel) 
    if (typeof maxLevel !== "number") maxLevel = 10
    for (var prop in obj) 
        if (typeof propsToRemove === "string" && prop === propsToRemove)
            delete obj[prop];
        else if (propsToRemove.indexOf(prop) >= 0)      // it must be an array
            delete obj[prop];
        else if (typeof obj[prop] === "object" && maxLevel>0)
            du.removeAllPropsFromObj(obj[prop], propsToRemove, maxLevel-1);
    
    return obj

【讨论】:

【参考方案7】:
// recursively delete a key from anywhere in the object
// will mutate the obj - no need to return it
const deletePropFromObj = (obj, deleteThisKey) => 
  if (Array.isArray(obj)) 
    obj.forEach(element => deletePropFromObj(element, deleteThisKey))
   else if (typeof obj === 'object') 
    for (const key in obj) 
      const value = obj[key]
      if (key === deleteThisKey) delete obj[key]
      else deletePropFromObj(value, deleteThisKey)
    
  


deletePropFromObj(obj, '$meta');

【讨论】:

以上是关于使用 JavaScript 从对象中递归删除属性和值的最快方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何从JavaScript对象中移除一个属性

从对象中删除属性 (JavaScript)

从对象中删除属性 (JavaScript)

从对象中删除属性 (JavaScript)

javascript 按对象属性从数组中删除JS对象

javascript 按属性从数组中删除对象