Remove empty properties / falsy values from Object with Underscore.js
Solution 1
You could make your own underscore plugin (mixin) :
_.mixin({
compactObject: function(o) {
_.each(o, function(v, k) {
if(!v) {
delete o[k];
}
});
return o;
}
});
And then use it as a native underscore method :
var o = _.compactObject({
foo: 'bar',
a: 0,
b: false,
c: '',
d: null,
e: undefined
});
Update
As @AndreiNeculau pointed out, this mixin affects the original object, while the original compact
underscore method returns a copy of the array.
To solve this issue and make our compactObject
behave more like it's cousin, here's a minor update:
_.mixin({
compactObject : function(o) {
var clone = _.clone(o);
_.each(clone, function(v, k) {
if(!v) {
delete clone[k];
}
});
return clone;
}
});
Solution 2
Since Underscore version 1.7.0, you can use _.pick
:
_.pick(sourceObj, _.identity)
Explanation
The second parameter to _.pick
can be a predicate function for selecting values. Values for which the predicate returns truthy are picked, and values for which the predicate returns falsy are ignored.
pick _.pick(object, *keys)
Return a copy of the object, filtered to only have values for the whitelisted keys (or array of valid keys). Alternatively accepts a predicate indicating which keys to pick.
_.identity
is a helper function that returns its first argument, which means it also works as a predicate function that selects truthy values and rejects falsy ones. The Underscore library also comes with a bunch of other predicates, for instance _.pick(sourceObj, _.isBoolean)
would retain only boolean properties.
If you use this technique a lot, you might want to make it a bit more expressive:
var pickNonfalsy = _.partial(_.pick, _, _.identity); // Place this in a library module or something
pickNonfalsy(sourceObj);
Underscore version 1.6.0 provided _.pick
as well, but it didn't accept a predicate function instead of a whitelist.
Solution 3
Quick 'n Clear: _.omitBy( source, i => !i );
This is stated in an inverse fashion to Emil's answer. This way imho reads clearer; it's more self explanatory.
Slightly less clean if you don't have the luxury of ES6: _.omitBy( source, function(i){return !i;});
Alternate: _.omitBy( source, _.isEmpty)
Using _.isEmpty
, instead of _.identity
for truthiness, will also conveniently remove empty arrays and objects from the collection and perhaps inconveniently remove numbers and dates. Thus the outcome is NOT an exact answer to the OP's question, however it could be useful when looking to remove empty collections.
Solution 4
With lodash's transform,
_.transform(obj, function(res, v, k) {
if (v) res[k] = v;
});
Solution 5
Object.keys(o).forEach(function(k) {
if (!o[k]) {
delete o[k];
}
});
Admin
Updated on October 03, 2021Comments
-
Admin over 2 years
I have an object with several properties. I would like to remove any properties that have falsy values.
This can be achieved with
compact
on arrays, but what about objects? -
Felix Kling over 11 yearsAnd one can use underscore for
.keys
and.forEach
. -
Admin over 11 yearsHow would this look in Underscore, then? Trying to piece it together…
-
gion_13 over 11 yearssince he wants an underscore solution, you could iterate over the array using one of underscore's methods
-
Anton almost 11 years+1 this is awesome man. please give me the link of
forEach
method of JS -
Florian Margaine almost 11 years
-
Andrei Neculau about 10 yearsSince the question has an underscore reference, it would be good to mention that this does not behave like
_.compact
. It will delete properties, rather than create a shallow clone with truthy values only. See stackoverflow.com/a/19750822/465684 below -
gion_13 about 10 years@AndreiNeculau You're right! I seem to have missed that earlier. See my updated answer.
-
evilive over 9 yearswhit lodash's _.pick(obj, _.identity); shorter ^_^
-
Radko Dinev over 9 yearsThis answer or @evilive's comment under it IS the answer.
-
Radko Dinev over 9 yearsWhy first copy all the properties of an object, then loop through them and delete falsy ones? That's unperformant. Moreover, using
delete
is generally discouraged as it immediately exposes properties with the same name from the prototype chain and also hurts performance due to "hidden classes" (V8) - changing the object structure causes the engine to do extra work. The best and shortest solution would be_.pick(o, _.identity)
. -
zaboco over 9 yearsa shorter variation, based on the above comment, would be
var compactObject = _.partialRight(_.pick, _.identity);
-
ivkremer about 9 yearsSpecial thanks for mentioning
_.identity
function, very handy. -
Ben Patterson almost 9 yearsThis has been extremely handy! It's also possible to use
_.omit(sourceObj, _.isUndefined)
to remove only undefined values (allowing false, null, 0). -
David Chase almost 9 yearsIts also possible to do
pick(obj, Boolean)
to eliminate falsey values that same approach can be used whenarr.filter(Boolean)
to clean an array from falsey values... -
Deniz Ozger over 8 yearsIn ES6, this turns into
_.pick(sourceObj, prop => prop)
-
zooblin over 8 yearsIn lodash 4.4.0
_.pick
works with property names, for this functionality as mentioned in post use_.pickBy
-
JackMorrissey almost 8 yearsIn Lodash 4.0, this functionality is now under
omitBy
. lodash.com/docs#omitBy -
laggingreflex over 7 years
-
Turadg over 7 yearsBut it still returns an array. The keys are lost.
-
tzvi over 7 yearsYou're right. Do I delete my answer then? Or does stackoverflow prefer something else?
-
Turadg over 7 yearsI don't know a community preference, but if you're fine with leaving it could have value of preventing someone else from adding a similar answer.
-
Jeff Lowery over 7 yearsI believe this is the same as:
_.pick(source, i => i);
which avoids the negation -
Shibumi about 6 years@JeffLowery This is even better, in Lodash, because the default predicate is the identity function!
_.pickBy(source)
is all that's needed. -
Jabran Saeed about 6 years0 is not a falsy value. this removes zero as well
-
Emil Lundberg about 6 yearsNo, 0 is a falsy value.
0 ? 'true' : 'false'
evaluates to'false'
. -
wdetac almost 6 yearsyse,
_.pickBy(object)
is all you need -
Sir.Nathan Stassen over 3 yearsNote: Numbers are considered empty.
_.isEmpty(5) === true
. Thus values that are numbers will be dropped.