如何使用lodash从对象中删除未定义和空值?

253

我有一个类似于以下的Javascript对象:

var my_object = { a:undefined, b:2, c:4, d:undefined };

如何删除所有未定义的属性?假属性应该保留。

27个回答

329
你可以简单地使用 _.omit() 链接 _.isUndefined_.isNull 组合函数,并通过惰性求值获取结果。 演示
var result = _(my_object).omit(_.isUndefined).omit(_.isNull).value();

2016年3月14日更新::

正如在评论区中dylants提到的那样,您应该使用_.omitBy()函数,因为它使用谓词而不是属性。 您应该在 lodash 版本 4.0.0 及以上使用此函数。

演示

var result = _(my_object).omitBy(_.isUndefined).omitBy(_.isNull).value();

2016年6月1日更新:

正如Max Truxa所评论的那样,lodash已经提供了一个替代方案_.isNil,它可以检查nullundefined两者:

var result = _.omitBy(my_object, _.isNil);

8
使用更新版本的lodash的用户应该使用omitBy函数代替omit函数。因此,应该使用_(my_object).omitBy(_.isUndefined).omitBy(_.isNull).value(); - dylants
48
自从 lodash 4.0.0 版本以后,您可以使用 _.isNil 来代替链接 _.isUndefined_.isNull。这使得代码更加简洁:var result = _.omitBy(my_object, _.isNil); - Max Truxa
2
Lodash的omitBypickBy性能差,所以应该优先选择后者,并且在迭代函数中反转条件。上面接受的答案就是正确的。 - Ernesto
2
OP的问题仅涉及“null”和“undefined”值。 “identity”谓词还将删除“false”值,因此,如果你简单地基于问题意图回答,则我认为我的回答没有问题。另外,如果我们讨论“性能”,默认情况下,“omitBy”只是调用带有否定“identity”谓词的“pickBy”。因此,在性能方面,它太小而不重要。 - ryeballar
8
可能对于一些人来说很琐碎,但对于其他人来说很重要:这不是递归的!如果您想在嵌套对象中省略空值,您需要实现一个递归调用。 - Nir Alfasi
显示剩余3条评论

260

如果你想要移除所有假值,那么最紧凑的方法如下:

对于Lodash 4.x及更高版本

_.pickBy({ a: null, b: 1, c: undefined }, _.identity);
>> Object {b: 1}

对于 遗留的 Lodash 3.x 版本:

_.pick(obj, _.identity);

_.pick({ a: null, b: 1, c: undefined }, _.identity);
>> Object {b: 1}

69
请注意,在 Lodash 4 中应该这样写:_.pickBy(obj, _.identity); - Tom Spencer
58
请注意,这种方法也会删除假值。 - unlimited
19
除了删除错误的内容外,它还会删除值为0和''(空字符串)的属性... 这不是一个好主意。 - Federico Budassi
11
这个答案不正确,因为它也会移除假值。请查看下面我的答案。 - Tiago Bértolo
5
为什么这是一个答案?它没有回答问题,同时删除了“0”和“false”值。 - Mads Buch
显示剩余3条评论

60

正确答案是:

_.omitBy({ a: null, b: 1, c: undefined, d: false }, _.isNil)

这导致:

{b: 1, d: false}

其他人提供的替代方案:

_.pickBy({ a: null, b: 1, c: undefined, d: false }, _.identity);

将删除这里不需要的false值。


{"a":1,"b":{"a":1,"b":null,"c":undefined}},对象的属性b中的bc将不被移除。 - mqliutie
2
@mqliutie 如预期所致。 - Tiago Bértolo

44

48
"compact"适用于数组,但问题是关于对象的。 - guidoman
1
除了0以外,其他都可以。啊,就差一点了。 - Sámal Rasmussen
2
@Sammi,在这种情况下,你可以使用_.pickBy(object, _.isNumber) - John Rix
1
谢谢 @Herick。 它有效。 我现在要去睡觉了。 - technophyle
1
@technophyle,我同意你的观点(而且这个答案就是我写的,哈)。但我会保留这个答案,因为它至少能够解决一些人的问题。 - JavaFish
显示剩余4条评论

26

只是:

_.omit(my_object, _.isUndefined)

上述内容未考虑null值,因为它们在原始示例中缺失且只在主题中提到,但我将保留它,因为它很优雅且可能有其用途。

以下是完整的示例,不那么简洁,但更加完整。

var obj = { a: undefined, b: 2, c: 4, d: undefined, e: null, f: false, g: '', h: 0 };
console.log(_.omit(obj, function(v) { return _.isUndefined(v) || _.isNull(v); }));

11
注意,这是针对 Lodash v.3 的。对于 v.4,您需要使用_.omitBy - PhiLho

23
为了补充其他答案,在lodash 4中,如果你只想忽略undefined和null(而不是像false这样的属性),你可以在 _.pickBy 中使用谓词:

_.pickBy(obj, v!== null && v!== undefined)

以下是示例:
const obj = { a: undefined, b: 123, c: true, d: false, e: null};

const filteredObject = _.pickBy(obj, v => v !== null && v !== undefined);

console.log = (obj) => document.write(JSON.stringify(filteredObject, null, 2));
console.log(filteredObject);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>


2
如果您不想删除 0''false 值,那么这是最佳解决方案。此外,您可以将回调缩短为 v => v != null - SimpleJ
2
简单的解决方案。谢谢你。 - Arjun G
这是非常好的、灵活的解决方案。谢谢。 - Gagan

12

根据Lodash文档:

_.compact(_.map(array, fn))

同时,您可以筛选掉所有的空值。


8

如果你需要处理深度嵌套的对象,可以使用我为lodash > 4编写的代码片段。

const removeObjectsWithNull = (obj) => {
    return _(obj)
      .pickBy(_.isObject) // get only objects
      .mapValues(removeObjectsWithNull) // call only for values as objects
      .assign(_.omitBy(obj, _.isObject)) // save back result that is not object
      .omitBy(_.isNil) // remove null and undefined from object
      .value(); // get value
};

这并没有移除一个值为null的嵌套对象,父键仍然没有值。 - JesseBoyd
这最初对我来说不起作用,因为它删除了日期和对象ID。所以我用isPlainObject替换了isObject的两个实例,看起来问题得到了解决。 - Daniel J. Lewis

8

纯JavaScript实现:(虽然Object.entries是ES7特性,Object.assign是ES6特性;但使用只有Object.keys的等效ES5应该也可以实现); 还要注意v != null检查null和undefined两种情况;

> var d = { a:undefined, b:2, c:0, d:undefined, e: null, f: 0.3, s: "", t: false };
undefined
> Object.entries(d)
    .filter(([ k, v ]) => (v != null))
    .reduce((acc, [k, v]) => Object.assign(acc, {[k]: v}), {})
{ b: 2, c: 0, f: 0.3, s: '', t: false }

编辑:以下是仅使用ES5 Object.keys的版本:但通常在Node v8中使用ES7相当令人愉悦 ;-)

> Object.keys(d)
    .filter(function(k) { return d[k] != null; })
    .reduce(function(acc, k) { acc[k] = d[k]; return acc; }, {});
{ b: 2, c: 0, f: 0.3, s: '', t: false }

2017年10月更新:随着Node v8的发布(从v8.3开始),现在它支持对象展开符构造:

> var d = { a:undefined, b:2, c:0, d:undefined,
    e: null, f: -0.0, s: "", t: false, inf: +Infinity, nan: NaN };
undefined
> Object.entries(d)
    .filter(([ k, v ]) => (v != null))
    .reduce((acc, [k, v]) => ({...acc, [k]: v}), {})
{ b: 2, c: 0, f: -0, s: '', t: false, inf: Infinity, nan: NaN }

或者仅在一个reduce中:

> Object.entries(d)
   .reduce((acc, [k, v]) => (v==null ? acc : {...acc, [k]: v}), {})
{ b: 2, c: 0, f: -0, s: '', t: false, inf: Infinity, nan: NaN }

更新:有人想要递归吗?这也不难,只需要增加一个isObject的附加检查,然后递归调用自身即可。
> function isObject(o) {
    return Object.prototype.toString.call(o) === "[object Object]"; }
undefined
> function dropNullUndefined(d) {
    return Object.entries(d)
      .reduce((acc, [k, v]) => (
        v == null ? acc :
         {...acc, [k]: (isObject(v) ? dropNullUndefined(v) : v) }
      ), {});
  }
> dropNullUndefined({a: 3, b:null})
{ a: 3 }
> dropNullUndefined({a: 3, b:null, c: { d: 0, e: undefined }})
{ a: 3, c: { d: 0 } }

我的结论是:如果纯JavaScript可以实现,我会避免使用任何第三方库依赖:


1
你可以使用 Object.fromEntries 来避免使用 reduce:Object.fromEntries(Object.entries(d).filter(([ k, v ]) => (v != null))) - ppierre
我仍然看到了父键。a: {b: null},a: 仍然存在 :( - JesseBoyd

7
从对象中删除undefined、null和空字符串
_.omitBy(object, (v) => _.isUndefined(v) || _.isNull(v) || v === '');

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