【问题标题】:Remove empty objects from an object从对象中删除空对象
【发布时间】:2021-12-06 22:09:59
【问题描述】:

我正在尝试删除对象内的空对象,这是一个具有预期输出的示例:

var object = {
    a: {
        b: 1,
        c: {
            a: 1,
            d: {},
            e: {
              f: {} 
            }
        }
    },
    b: {}
}


var expectedResult = {
    a: {
        b: 1,
        c: {
            a: 1,
        }
    }
}

我尝试使用其他 StackOverflow 问题中的一些示例,但这些示例仅适用于一级对象。

【问题讨论】:

  • 使用递归函数。如果您有一个函数接收一个对象并对其进行迭代以查找空对象并删除它们,那么当涉及到一个非空对象时,只需使用该内部对象作为参数调用相同的函数。
  • @squint 请给我一个例子,我仍然是 javascript 的初学者,正在努力赶上。l

标签: javascript node.js underscore.js


【解决方案1】:

删除空对象的基本函数

首先从一个只适用于单层嵌套的函数开始。

此函数删除所有引用空对象的属性:

function clearEmpties(o) {
  for (var k in o) {
    if (!o[k] || typeof o[k] !== "object") {
      continue // If null or not an object, skip to the next iteration
    }

    // The property is an object
    if (Object.keys(o[k]).length === 0) {
      delete o[k]; // The object had no properties, so delete that property
    }
    return o;
  }
}

使用递归处理嵌套对象

现在你想让它递归,以便它可以对嵌套对象进行操作。所以我们已经测试了o[k] 是否是一个对象,并且我们已经测试了是否有属性,所以如果有,我们只需使用该嵌套对象再次调用该函数。

function clearEmpties(o) {
  for (var k in o) {
    if (!o[k] || typeof o[k] !== "object") {
      continue // If null or not an object, skip to the next iteration
    }

    // The property is an object
    clearEmpties(o[k]); // <-- Make a recursive call on the nested object
    if (Object.keys(o[k]).length === 0) {
      delete o[k]; // The object had no properties, so delete that property
    }
  }
    return o;
}

因此,正如对 clearEmpties 的原始调用会删除引用空对象的给定对象的属性一样,递归调用也会对嵌套对象执行相同的操作。


现场演示:

var object = {
  a: {
    b: 1,
    c: {
      a: 1,
      d: {},
      e: { // will need to be removed after f has been removed
         f: {} 
      }
    }
  },

  b: {}
};

clearEmpties(object);
console.log(object);

function clearEmpties(o) {
  for (var k in o) {
    if (!o[k] || typeof o[k] !== "object") {
      continue
    }

    clearEmpties(o[k]);
    if (Object.keys(o[k]).length === 0) {
      delete o[k];
    }
  }
  return o;
}

使用下划线和函数式风格的短版

function clearEmpties(o) {
  if (_.isFunction(o) || !_.isObject(o)) return o;
  return _.chain(o)
    .mapObject(clearEmpties)
    .pick(p => !(_.isObject(p) && _.isEmpty(p)))
    .value();
}

使用 lodash 和函数式风格的短版本 - 与 treeshaking 一起使用

import { isFunction, isObject, isEmpty, isArray, isPlainObject, fromPairs } from "lodash-es";

const removeEmtpyObjects = (o) => {
    if (isFunction(o) || !isPlainObject(o)) return o;

    if (isArray(o)) return o.map(removeEmtpyObjects);

    return fromPairs(
        Object.entries(o)
            .map(([k, v]) => [k, removeEmtpyObjects(v)])
            .filter(([k, v]) => !(v == null || (isObject(v) && isEmpty(v))))
    );
};

【讨论】:

  • 我认为你应该return o 不?
  • @GeorgiK.: 没必要,因为你想要做的就是用delete 改变现有的对象结构。但是,如果您希望它返回原始对象,您当然可以让它这样做。
  • 我试过了,带 {} 的对象仍然存在
  • 终于找到了我要找的词:"arm's length recursion",并在quora.com 上找到了对它的看法。
  • 请注意,这也会删除 Date 属性,它们也是对象。使用类似Object.prototype.toString.call(o[k]) != '[object Object]'
【解决方案2】:

我遇到了同样的问题,另外我的对象可能包含需要删除的空元素的数组。

我最终得到了这个快速而肮脏的解决方案。

如果您想定义“空”对您意味着什么,我还添加了一个不同的功能。就我而言,我还需要空字符串。

  function isEmpty(obj) {
        if (obj === '' || obj === null || JSON.stringify(obj) === '{}' || JSON.stringify(obj) === '[]' || (obj) === undefined || (obj) === {}) {
            return true
        } else {
            return false
        }
    }
    function removeEmpty(o) {
        if (typeof o !== "object") {
            return o;
        }
        let oKeys = Object.keys(o)
        for (let j = 0; j < oKeys.length; j++) {
            let p = oKeys[j]
            switch (typeof (o[p])) {
                case 'object':
                    if (Array.isArray(o[p])) {
                        for (let i = 0; i < o[p].length; i++) {
                            o[p][i] = removeEmpty(o[p][i])
                            if (isEmpty(o[p][i])) {
                                o[p].splice(i, 1)
                                i--
                            }
                        }
                        if (o[p].length === 0) {
                            if (Array.isArray(o)) {
                                o.splice(parseInt(p), 1)
                                j--
                            } else {
                                delete o[p]
                            }
                        }
                    } else {
                        if (isEmpty(o[p])) {
                            delete o[p]
                        } else {
                            o[p] = removeEmpty(o[p])
                            if (isEmpty(o[p])) {
                                delete o[p]
                            }
                        }
                    }
                    break
                default:
                    if (isEmpty(o[p])) {
                        delete o[p]
                    }
                    break
            }
    
        }
        if (Object.keys(o).length === 0) {
            return
        }
        return o
    }

输入:

var a = {
b: 1,
c: {
    d: [1, [[], [], [[[1], []]]], [2, [[], [[]]]], [], [[]]]
},
e: {
    f: [{}, { g: 1 }]
},
h: {
    i: { j: { k: undefined, l: null, m: { n: "", o: 1 } } }
},
p: { q: { r: 1 } }
}
removeEmpty(a)

输出:

   {
    "b": 1,
    "c": {
        "d": [1, [[[[1]]]], [2]]
    },
    "e": {
        "f": [{"g": 1}]
    },
    "h": {
        "i": {
            "j": {
                "m": {
                    "o": 1
                }
            }
        }
    },
    "p": {
        "q": {
            "r": 1
        }
    }
}

【讨论】:

    【解决方案3】:
    function clean(obj) {
      for (var propName in obj) { 
        if (obj[propName] === null || obj[propName] === undefined) {
          delete obj[propName];      }
      }
    }
    

    编辑:

    function clean(obj) {
          for (var propName in obj) {
            if(typeof obj[propName]=="object")
              clean(obj[propName])
            if (obj[propName] === null || obj[propName] === undefined) 
              delete obj[propName];      
           }
        }
    

    【讨论】:

    • obj[propName] === undefined || obj[propName] === undefined ?
    • 您可以使用if (obj[propName] == null) { 同时处理这两种情况。如果属性是或者 nullundefined,它将是true。但是,您的解决方案不检查 OP 正在寻找什么,也不处理嵌套对象。
    • 仍然没有清理我的 {},它们保持原样。 :(
    • 现在应该怎么做?您显示了 2 个完全不同的版本,并且没有任何书面解释
    • @charlietfl 你有解决办法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 2016-11-26
    • 1970-01-01
    • 2021-06-15
    • 2021-03-11
    • 1970-01-01
    • 2015-12-24
    相关资源
    最近更新 更多