从Javascript对象中删除空白属性


Answers:


184

您可以遍历对象:

var test = {
    test1 : null,
    test2 : 'somestring',
    test3 : 3,
}

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

clean(test);

如果您担心此属性删除不会使对象的proptype链运行起来,则还可以:

function clean(obj) {
  var propNames = Object.getOwnPropertyNames(obj);
  for (var i = 0; i < propNames.length; i++) {
    var propName = propNames[i];
    if (obj[propName] === null || obj[propName] === undefined) {
      delete obj[propName];
    }
  }
}

有关null与未定义的一些注意事项:

test.test1 === null; // true
test.test1 == null; // true

test.notaprop === null; // false
test.notaprop == null; // true

test.notaprop === undefined; // true
test.notaprop == undefined; // true

2
添加了快速更正。如果在功能中使用过此代码段,则未声明的“ i”变量将泄漏到外部作用域中。
埃里克·阮

4
您可以将(test [i] === null || test [i] === undefined)简化为(test [i] == null)
jaf0 2015年

您好,@EricNguyen,不同于C等几种语言,JavaScript并没有对变量块范围(仅功能范围),因此,可变将总是泄漏到后的范围块。
盖拉多·利马

1
@GerardoLima,是的。我有点假设这将全部包装在一个函数中。我的意思是(假设所有这些都用函数包装)是您需要var声明,否则将在函数范围之外泄漏信息。
Eric Nguyen

这也将遍历原始对象的原型-在大多数情况下是不希望的。stackoverflow.com/a/2869372/1612318
Rotareti '16

427

使用一些ES6 / ES2015

1)一个简单的单线即可在不分配的情况下内联删除项目:

Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);

jsbin

2)此示例已删除...

3)作为函数编写的第一个示例:

const removeEmpty = obj => {
  Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};

jsbin

4)此函数还使用递归从嵌套对象中删除项目:

const removeEmpty = obj => {
  Object.keys(obj).forEach(key => {
    if (obj[key] && typeof obj[key] === "object") removeEmpty(obj[key]); // recurse
    else if (obj[key] == null) delete obj[key]; // delete
  });
};

jsbin

4b)与4)类似,但是它不直接变异源对象,而是返回一个新对象。

const removeEmpty = obj => {
  const newObj = {};

  Object.keys(obj).forEach(key => {
    if (obj[key] && typeof obj[key] === "object") {
      newObj[key] = removeEmpty(obj[key]); // recurse
    } else if (obj[key] != null) {
      newObj[key] = obj[key]; // copy value
    }
  });

  return newObj;
};

5)基于@ MichaelJ.Zoidl使用和的答案的 4b )的一种功能方法。这个也返回一个新对象:filter()reduce()

const removeEmpty = obj =>
  Object.keys(obj)
    .filter(k => obj[k] != null) // Remove undef. and null.
    .reduce(
      (newObj, k) =>
        typeof obj[k] === "object"
          ? { ...newObj, [k]: removeEmpty(obj[k]) } // Recurse.
          : { ...newObj, [k]: obj[k] }, // Copy value.
      {}
    );

jsbin

6)与4)相同,但使用的是ES7 / 2016 Object.entries()

const removeEmpty = (obj) => 
  Object.entries(obj).forEach(([key, val]) => {
    if (val && typeof val === 'object') removeEmpty(val)
    else if (val == null) delete obj[key]
})

5b) 使用递归并使用ES2019返回新对象的另一个功能版本 : Object.fromEntries()

const removeEmpty = obj =>
  Object.fromEntries(
    Object.entries(obj)
      .filter(([k, v]) => v != null)
      .map(([k, v]) => (typeof v === "object" ? [k, removeEmpty(v)] : [k, v]))
  );

7)与4)相同,但在普通ES5中

function removeEmpty(obj) {
  Object.keys(obj).forEach(function(key) {
    if (obj[key] && typeof obj[key] === 'object') removeEmpty(obj[key])
    else if (obj[key] == null) delete obj[key]
  });
};

jsbin


3
@AugustinRiedinger当我不得不在换行符和缩写之间做出选择时,如果我认为该缩写是次要的邪恶,我有时会选择该缩写。在5代码)不难推理,这是一个函数,删除空keysobject,所以ok是显而易见的。但是我想这是一个品味问题。
罗塔蒂2013年

3
具有ES5风味的第一版:Object.keys(myObj).forEach(function (key) {(myObj[key] == null) && delete myObj[key]});
神经递质

1
一行,没有任何功能:Object.entries(myObj).reduce((acc, [key, val]) => { if (val) acc[key] = val; return acc; }, {})
保罗·萨姆

7
由于我们试图做到周密,因此看到一个不变的解决方案可能会很高兴。这些正在使源对象发生变异,并且正在欺骗性地返回实际上不必要的对象,因为该对象已发生变异。初学者将捕获返回的对象值,并想知道为什么还要修改其源对象。
Mike McLin

2
5)不适用于数组(Object.keys将返回数组位置编号作为元素的键)。可能其他人也有此问题,但我在测试5时发现了这个问题
。– Eelco

95

如果您使用lodash或underscore.js,这是一个简单的解决方案:

var obj = {name: 'John', age: null};

var compacted = _.pickBy(obj);

这仅适用于lodash 4,pre lodash 4或underscore.js,请使用_.pick(obj, _.identity)


1
辉煌!谢谢!仅供参考,对我来说不明显的是,您也可以像这样使用它:foo()。then(_。pickBy); //过滤掉空结果
Maciej Gurban '16

29
请注意,如果对象包含伪造的值(例如0或空字符串),则将不会获得期望的结果。那就_.omit(obj, _.isUndefined)更好了。
JHH

5
@JHH _.isUndefined没有遗漏空值,使用_.omitBy(obj, _.isNil)省略这两个undefinednull
卢卡斯Wiktor的

@LukaszWiktor正确,问题确实要求未定义或为null。
JHH

85

适用于ES6 +的最短衬管

过滤所有falsy值(""0falsenullundefined

Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})

过滤器nullundefined值:

Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {})

仅过滤 null

Object.entries(obj).reduce((a,[k,v]) => (v === null ? a : (a[k]=v, a)), {})

仅过滤 undefined

Object.entries(obj).reduce((a,[k,v]) => (v === undefined ? a : (a[k]=v, a)), {})

递归解决方案:过滤器nullundefined

对于对象:

const cleanEmpty = obj => Object.entries(obj)
        .map(([k,v])=>[k,v && typeof v === "object" ? cleanEmpty(v) : v])
        .reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {});

对于对象和数组:

const cleanEmpty = obj => {
  if (Array.isArray(obj)) { 
    return obj
        .map(v => (v && typeof v === 'object') ? cleanEmpty(v) : v)
        .filter(v => !(v == null)); 
  } else { 
    return Object.entries(obj)
        .map(([k, v]) => [k, v && typeof v === 'object' ? cleanEmpty(v) : v])
        .reduce((a, [k, v]) => (v == null ? a : (a[k]=v, a)), {});
  } 
}

10
这应该是唯一的答案!这些片段中的每一个都会生成一个新对象,其中旧对象不会发生突变。这是可取的!如果您只是使用一点注释v == null,将对照undefined和进行检查null
Megajin

cleanEmptyrecursve解决方案将返回一个空的对象{}为Date对象
灵光NK

一根衬里的易读性会让它们很棒!
zardilior

39

如果有人需要Owen(和Eric)答案的递归版本,则为:

/**
 * Delete all null (or undefined) properties from an object.
 * Set 'recurse' to true if you also want to delete properties in nested objects.
 */
function delete_null_properties(test, recurse) {
    for (var i in test) {
        if (test[i] === null) {
            delete test[i];
        } else if (recurse && typeof test[i] === 'object') {
            delete_null_properties(test[i], recurse);
        }
    }
}

for循环开始之后,您应该hasOwnProperty使用if(test.hasOwnProperty(i)) { ... }
Augie Gardner

@AugieGardner我很好奇您为什么要检查此内容-如果您愿意,请解释一下。(这是否会阻止检查继承的属性?)
Wumms,2016年

24

JSON.stringify删除未定义的键。

removeUndefined = function(json){
  return JSON.parse(JSON.stringify(json))
}

对于一个深层的对象,这对我没有用,但是上面的Wumm答案确实有用
苏曼

1
如果你需要null被视为undefined使用替换功能,更多信息请参阅本答案:stackoverflow.com/questions/286141/...
Hooman阿斯卡里

请注意,这不会删除null值。尝试:let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }然后console.log(removeUndefined(a))。问题是关于undefinednull价值观。
mayid

13

您可能正在寻找delete关键字。

var obj = { };
obj.theProperty = 1;
delete obj.theProperty;

4
这是他在上面所做的事情,这在对象中仍然没有定义。
2014年

10

Lodash解决方案最简单的解决方案,可返回过滤出nullundefined值的对象。

_.omitBy(obj, _.isNil)


这是迄今为止最干净的解决方案!
吉莫(Jee Mok)

9

您可以结合使用JSON.stringify其replacer参数,并将JSON.parse其变回一个对象。使用此方法还意味着将对嵌套对象中的所有嵌套键进行替换。

示例对象

var exampleObject = {
  string: 'value',
  emptyString: '',
  integer: 0,
  nullValue: null,
  array: [1, 2, 3],
  object: {
    string: 'value',
    emptyString: '',
    integer: 0,
    nullValue: null,
    array: [1, 2, 3]
  },
  arrayOfObjects: [
    {
      string: 'value',
      emptyString: '',
      integer: 0,
      nullValue: null,
      array: [1, 2, 3]
    },
    {
      string: 'value',
      emptyString: '',
      integer: 0,
      nullValue: null,
      array: [1, 2, 3]
    }
  ]
};

替代功能

function replaceUndefinedOrNull(key, value) {
  if (value === null || value === undefined) {
    return undefined;
  }

  return value;
}

清洁物体

exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);

CodePen示例


6

使用ramda#pickBy你会删除所有nullundefinedfalse值:

const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)

正如@manroe所指出的,要保留false值,请使用isNil()

const obj = {a:1, b: undefined, c: null, d: 1, e: false}
R.pickBy(v => !R.isNil(v), obj)

1
(v) => !R.isNil(v)考虑到OP false或其他虚假的值也将被R.identity
Manroe '18

6

功能性和不变性的方法,.filter无需创建或不创建超出所需数量的对象

Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})

答案很简洁。要添加空检查,只需替换obj[key] === undefinedobj[key] === undefined || obj[key] === null
user3658510

上述办法的一个微小的变化:你也可以有条件地散布在truthy OBJ财产像这样const omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
凯文·K.

5

你可以根据!条件做得更短

var r = {a: null, b: undefined, c:1};
for(var k in r)
   if(!r[k]) delete r[k];

记住用法:@semicolor在注释中宣布:如果值是空字符串,false或零,这也会删除属性


11
如果值为空字符串,false或零,则这也会删除属性。
分号

3
这正是我想要从JSON请求中删除不需要的字段的内容。谢谢!
Phrozen 2014年

使用[null, undefined].includes(r[k])代替!r[k]
selmansamet

5

较短的ES6纯解决方案,将其转换为数组,使用过滤器功能,然后将其转换回对象。容易实现功能...

顺便说一句。与此,.length > 0我检查是否有一个空字符串/数组,所以它将删除空键。

const MY_OBJECT = { f: 'te', a: [] }

Object.keys(MY_OBJECT)
 .filter(f => !!MY_OBJECT[f] && MY_OBJECT[f].length > 0)
 .reduce((r, i) => { r[i] = MY_OBJECT[i]; return r; }, {});

JS BIN https://jsbin.com/kugoyinora/edit?js,控制台


1
好的功能解决方案
Puiu

我喜欢这个!但是我想删除所有内容null,使用undefined起来会更简单MY_OBJECT[f] != null。您当前的解决方案会删除除非空字符串/列表以外的所有内容,并在值是null
Rotareti

是的,您还可以使用/链接多个filter,这样可读性更好。
Michael J. Zoidl

如果稍微概括一下,我认为您已经接近loadash的omit功能,则在调用之前确实需要检查obj是否存在Object.keysconst omit = (obj, filter) => obj && Object.keys(obj).filter(key => !filter(obj[key])).reduce((acc,key) => {acc[key] = obj[key]; return acc}, {});
icc97

不错,但是任何整数值都可以用这种方法删除。
Ghis

5

您可以使用json.stringify的replacer参数在一行中进行递归删除

const removeNullValues = obj => (
  JSON.parse(JSON.stringify(obj, (k,v) => v ?? undefined))
)

用法:

removeNullValues({a:{x:1,y:null,z:undefined}}) // Returns {a:{x:1}}

如Emmanuel的评论中所述,仅当您的数据结构仅包含可放入JSON格式的数据类型(字符串,数字,列表等)时,此技术才有效。

(这个答案已经更新为使用新Nullish合并运算根据浏览器支持的需求可能要使用此功能代替。(k,v) => v!=null ? v : undefined


1
这会将Date对象转换为字符串,并将其转换NaNnull不删除的字符串。
伊曼纽尔·NK

4

如果您需要4行纯ES7解决方案:

const clean = e => e instanceof Object ? Object.entries(e).reduce((o, [k, v]) => {
  if (typeof v === 'boolean' || v) o[k] = clean(v);
  return o;
}, e instanceof Array ? [] : {}) : e;

或者,如果您喜欢可读性更高的版本:

function filterEmpty(obj, [key, val]) {
  if (typeof val === 'boolean' || val) {
    obj[key] = clean(val)
  };

  return obj;
}

function clean(entry) {
  if (entry instanceof Object) {
    const type = entry instanceof Array ? [] : {};
    const entries = Object.entries(entry);

    return entries.reduce(filterEmpty, type);
  }

  return entry;
}

这将保留布尔值,也将清除数组。它还通过返回已清除的副本来保留原始对象。


4

我的项目中有相同的场景,并使用以下方法实现。

它适用于所有数据类型,上面提到的少数不适用于date和empty arrays。

removeEmptyKeysFromObject.js

removeEmptyKeysFromObject(obj) {
   Object.keys(obj).forEach(key => {
  if (Object.prototype.toString.call(obj[key]) === '[object Date]' && (obj[key].toString().length === 0 || obj[key].toString() === 'Invalid Date')) {
    delete obj[key];
  } else if (obj[key] && typeof obj[key] === 'object') {
    this.removeEmptyKeysFromObject(obj[key]);
  } else if (obj[key] == null || obj[key] === '') {
    delete obj[key];
  }

  if (obj[key]
    && typeof obj[key] === 'object'
    && Object.keys(obj[key]).length === 0
    && Object.prototype.toString.call(obj[key]) !== '[object Date]') {
    delete obj[key];
  }
});
  return obj;
}

将任何对象传递给此函数removeEmptyKeysFromObject()


4

对于深度搜索,我使用了以下代码,也许对查看此问题的任何人都有用(不适用于循环依赖项):

function removeEmptyValues(obj) {
        for (var propName in obj) {
            if (!obj[propName] || obj[propName].length === 0) {
                delete obj[propName];
            } else if (typeof obj[propName] === 'object') {
                removeEmptyValues(obj[propName]);
            }
        }
        return obj;
    }

3

如果您不想在原处进行突变,而是返回一个删除了null / undefined的克隆,则可以使用ES6 reduce函数。

// Helper to remove undefined or null properties from an object
function removeEmpty(obj) {
  // Protect against null/undefined object passed in
  return Object.keys(obj || {}).reduce((x, k) => {
    // Check for null or undefined
    if (obj[k] != null) {
      x[k] = obj[k];
    }
    return x;
  }, {});
}

3

除了删除属性,您还可以使用不为null的键创建一个新对象。

const removeEmpty = (obj) => {
  return Object.keys(obj).filter(key => obj[key]).reduce(
    (newObj, key) => {
      newObj[key] = obj[key]
      return newObj
    }, {}
  )
}

3

要在piggypack Ben的回答如何解决使用lodash的这个问题_.pickBy,也可以解决的姐妹库这个问题:Underscore.js_.pick

var obj = {name: 'John', age: null};

var compacted = _.pick(obj, function(value) {
  return value !== null && value !== undefined;
});

请参阅:JSFiddle示例


1
这将返回空数组,您也将obj的名称更改为object
Stephen DuMont

谢谢斯蒂芬!现在怎么样?我已经更新了答案,以包含一个JSFiddle链接。
亚历克·约翰逊

尝试使用_.omit(obj,_.isEmpty); 从概念上讲,这是纯净的,将包含空字符串。
史蒂芬·杜蒙特(Steven DuMont)

3

减少助手可以解决问题(无需类型检查)-

const cleanObj = Object.entries(objToClean).reduce((acc, [key, value]) => {
      if (value) {
        acc[key] = value;
      }
      return acc;
    }, {});

2

如果有人需要undefined使用深度搜索从对象中删除值,lodash那么这里是我正在使用的代码。修改它以删除所有空值(null/ undefined)非常简单。

function omitUndefinedDeep(obj) {
  return _.reduce(obj, function(result, value, key) {
    if (_.isObject(value)) {
      result[key] = omitUndefinedDeep(value);
    }
    else if (!_.isUndefined(value)) {
      result[key] = value;
    }
    return result;
  }, {});
}


1

如果您使用eslint并希望避免触发no-param-reassign规则,则可以将Object.assign与.reduce和计算的属性名称结合使用,以获得相当优雅的ES6解决方案:

const queryParams = { a: 'a', b: 'b', c: 'c', d: undefined, e: null, f: '', g: 0 };
const cleanParams = Object.keys(queryParams) 
  .filter(key => queryParams[key] != null)
  .reduce((acc, key) => Object.assign(acc, { [key]: queryParams[key] }), {});
// { a: 'a', b: 'b', c: 'c', f: '', g: 0 }

1

这是nulls使用ES6从对象中删除而不用仅更改对象的一种有效方法reduce

const stripNulls = (obj) => {
  return Object.keys(obj).reduce((acc, current) => {
    if (obj[current] !== null) {
      return { ...acc, [current]: obj[current] }
    }
    return acc
  }, {})
}

巨魔评论关于这是一种功能模式的两件事:在stripNulls函数内部,它使用了累加器函数范围之外的引用;并且还通过在累加器函数中进行过滤来混合关注点。😝(例如Object.entries(o).filter(([k,v]) => v !== null).reduce((o, [k, v]) => {o[k] = v; return o;}, {});是,它将对过滤的项目进行两次循环,但是实际的性能损失可以忽略不计。
杰森·库斯特

1

您还可以通过以下方式使用...传播语法forEach

let obj = { a: 1, b: "b", c: undefined, d: null };
let cleanObj = {};

Object.keys(obj).forEach(val => {
  const newVal = obj[val];
  cleanObj = newVal ? { ...cleanObj, [val]: newVal } : cleanObj;
});

console.info(cleanObj);

1

清洁物体

// General cleanObj function
const cleanObj = (valsToRemoveArr, obj) => {
   Object.keys(obj).forEach( (key) =>
      if (valsToRemoveArr.includes(obj[key])){
         delete obj[key]
      }
   })
}

cleanObj([undefined, null], obj)

纯功能

const getObjWithoutVals = (dontReturnValsArr, obj) => {
    const cleanObj = {}
    Object.entries(obj).forEach( ([key, val]) => {
        if(!dontReturnValsArr.includes(val)){
            cleanObj[key]= val
        } 
    })
    return cleanObj
}

//To get a new object without `null` or `undefined` run: 
const nonEmptyObj = getObjWithoutVals([undefined, null], obj)

这是一个很好的解决方案,可能是
单线

1

我们可以使用JSON.stringify和JSON.parse从对象中删除空白属性。

jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
               if (value == null || value == '' || value == [] || value == {})
                   return undefined;
               return value;
           });

只要您确保Obj是JSON可序列化的,此技巧实际上是有效的。而且它的作用也很深。
投票

无效的数组和对象比较({} != {}[] != []),但否则方法有效
Aivaras

1

这是一个综合的递归函数(最初基于@chickens的函数),它将:

  • 递归删除您告诉的内容 defaults=[undefined, null, '', NaN]
  • 正确处理常规对象,数组和日期对象
const cleanEmpty = function(obj, defaults = [undefined, null, NaN, '']) {
  if (!defaults.length) return obj
  if (defaults.includes(obj)) return

  if (Array.isArray(obj))
    return obj
      .map(v => v && typeof v === 'object' ? cleanEmpty(v, defaults) : v)
      .filter(v => !defaults.includes(v))

  return Object.entries(obj).length 
    ? Object.entries(obj)
        .map(([k, v]) => ([k, v && typeof v === 'object' ? cleanEmpty(v, defaults) : v]))
        .reduce((a, [k, v]) => (defaults.includes(v) ? a : { ...a, [k]: v}), {}) 
    : obj
}

用法:

// based off the recursive cleanEmpty function by @chickens. 
// This one can also handle Date objects correctly 
// and has a defaults list for values you want stripped.

const cleanEmpty = function(obj, defaults = [undefined, null, NaN, '']) {
  if (!defaults.length) return obj
  if (defaults.includes(obj)) return

  if (Array.isArray(obj))
    return obj
      .map(v => v && typeof v === 'object' ? cleanEmpty(v, defaults) : v)
      .filter(v => !defaults.includes(v))

  return Object.entries(obj).length 
    ? Object.entries(obj)
        .map(([k, v]) => ([k, v && typeof v === 'object' ? cleanEmpty(v, defaults) : v]))
        .reduce((a, [k, v]) => (defaults.includes(v) ? a : { ...a, [k]: v}), {}) 
    : obj
}


// testing

console.log('testing: undefined \n', cleanEmpty(undefined))
console.log('testing: null \n',cleanEmpty(null))
console.log('testing: NaN \n',cleanEmpty(NaN))
console.log('testing: empty string \n',cleanEmpty(''))
console.log('testing: empty array \n',cleanEmpty([]))
console.log('testing: date object \n',cleanEmpty(new Date(1589339052 * 1000)))
console.log('testing: nested empty arr \n',cleanEmpty({ 1: { 2 :null, 3: [] }}))
console.log('testing: comprehensive obj \n', cleanEmpty({
  a: 5,
  b: 0,
  c: undefined,
  d: {
    e: null,
    f: [{
      a: undefined,
      b: new Date(),
      c: ''
    }]
  },
  g: NaN,
  h: null
}))
console.log('testing: different defaults \n', cleanEmpty({
  a: 5,
  b: 0,
  c: undefined,
  d: {
    e: null,
    f: [{
      a: undefined,
      b: '',
      c: new Date()
    }]
  },
  g: [0, 1, 2, 3, 4],
  h: '',
}, [undefined, null]))


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.