如何从对象中深度删除空值,空对象和空数组

时间:2018-09-04 23:34:28

标签: javascript

我有一个看起来像这样的对象:

var myObject = { a: { b: [{}], c: [{}, {d: 2}], e: 2, f: {} }, g:{}, h:[], i: [null, 2] }

我想删除空值和空对象(数组和对象),使其看起来像:

{ a: {c: [ {d: 2} ], e: 2 }, i: [ 2 ] }

该函数应删除空值,空对象和空数组。有什么优雅的方法吗?

3 个答案:

答案 0 :(得分:0)

这是一个递归清除对象的函数。它将深入遍历所有属性,并删除空值,空数组和空对象:

cleanUpObject(jsonObject: object): object {

    Object.keys(jsonObject).forEach(function (key, index) {
        const currentObj = jsonObject[key]

        if (_.isNull(currentObj)) {
            delete jsonObject[key]
        } else if (_.isObject(currentObj)) {
            if (_.isArray(currentObj)) {
                if (!currentObj.length) {
                    delete jsonObject[key]
                } else {
                    const cleanupArrayObj = []
                    for (const obj of currentObj) {
                        if (!_.isNull(obj)) {
                            const cleanObj = this.cleanUpJson(obj)
                            if (!_.isEmpty(cleanObj)) {
                                cleanupArrayObj.push(cleanObj)
                            }
                        }
                    }
                    if (!cleanupArrayObj.length) {
                        delete jsonObject[key]
                    } else {
                        jsonObject[key] = cleanupArrayObj
                    }
                }
            } else {
                if (_.isEmpty(Object.keys(jsonObject[key]))) {
                    delete jsonObject[key]
                } else {
                    jsonObject[key] = this.cleanUpJson(currentObj)

                    if (_.isEmpty(Object.keys(jsonObject[key]))) {
                        delete jsonObject[key]
                    }
                }
            }
        }
    }, this)

    return jsonObject
}

答案 1 :(得分:0)

为减少重复代码,一种选择是定义一个函数(我们将其称为itemToBool),该函数可以确定传递给它的泛型值是真实的还是 somewhere 的递归真实,该值应该是数组还是对象。然后,在传递原始对象的函数(或递归传递对象或数组的函数)中,只要有值需要验证,就可以调用该itemToBool函数。

对于数组,mapitemToBool,然后filter乘布尔。对于对象,将对象的reduce entries转换为另一个对象:将对象的每个值通过itemToBool进行递归转换(如果值是数组或对象),并且如果转换后的值具有任何键(或者是真实的原语),则将其分配给累加器。无需依赖库:

var myObject = {
  a: {
    b: [{}],
    c: [{}, {
      d: 2
    }],
    e: 2,
    f: {}
  },
  g: {},
  h: [],
  i: [null, 2]
};

// Returns a falsey value if the item is falsey,
// or if the deep cleaned array or object is empty:
const itemToBool = item => {
  if (typeof item !== 'object' || item === null) return item;
  const cleanedItem = clean(item);
  return Object.keys(cleanedItem).length !== 0 && cleanedItem;
};

const clean = obj => {
  if (Array.isArray(obj)) {
    const newArr = obj.map(itemToBool).filter(Boolean);
    return newArr.length && newArr;
  }
  const newObj = Object.entries(obj).reduce((a, [key, val]) => {
    const newVal = itemToBool(val);
    if (newVal) a[key] = newVal;
    return a;
  }, {});
  return Object.keys(newObj).length > 0 && newObj;
};

console.log(clean(myObject));

嗯...您还可以将对键数的检查也抽象为一个函数:

var myObject={a:{b:[{}],c:[{},{d:2}],e:2,f:{}},g:{},h:[],i:[null,2]}

// Returns the object / array if it has at least one key, else returns false:
const validObj = obj => Object.keys(obj).length && obj;
const itemToBool = item => (
  typeof item !== 'object' || item === null
  ? item
  : validObj(clean(item))
);
const clean = obj => validObj(
  Array.isArray(obj)
  ? obj.map(itemToBool).filter(Boolean)
  : Object.entries(obj).reduce((a, [key, val]) => {
      const newVal = itemToBool(val);
      if (newVal) a[key] = newVal;
      return a;
    }, {})
);

console.log(clean(myObject));

答案 2 :(得分:0)

我们不知道您所说的 clean 是什么意思,但是据我了解,您想删除所有null和空值。此算法很简单:递归检查并删除任何空值/ null值(它们会递归检查)。

function clean(obj) {
  // clean array
  if (Array.isArray(obj)) {
    for (let i=0; i<obj.length; i++) {
      if (isNothing(obj[i])) obj.splice(i, 1);  // remove value if falsy
      else if (typeof obj[i] === 'object') clean(obj[i]); // recurse if it's a truthy object
    }
    
  // clean other object
  } else {
    for (let prop in obj) {
      if (!obj.hasOwnProperty(prop)) continue;
      if (isNothing(obj[prop])) delete obj[prop]; // remove value if falsy
      else if (typeof obj[prop] === 'object') clean(obj[prop]); // recurse if it's a truthy object
    }
  }
}

// Recursively check for populated or nonnull content. If none found, return `true`. Recursive so [{}] will be treated as empty.
function isNothing(item) {
  // null / undefined
  if (item == null) return true;
  
  // deep object falsiness
  if (typeof item === 'object') {
    if (Array.isArray(item)) {
      // array -> check for populated/nonnull value
      for (let i=0; i<item.length; i++) {
        if (!isNothing(item[i])) return false;
      }
      return true;
    }
    // other object -> check for populated/nonnull value
    for (let prop in item) {
      if (!item.hasOwnProperty(prop)) continue;
      if (!isNothing(item[prop])) return false;
    }
    return true;
  }
  return false;
}

var myObject = { a: { b: [{}], c: [{}, {d: 2}], e: 2, f: {} }, g:{}, h:[], i: [null, 2] };

console.log("Before: " + JSON.stringify(myObject));
clean(myObject);
console.log("After: " + JSON.stringify(myObject));