How to check if a value is empty using Lodash

How to check if a value is empty using Lodash

When you’re dealing with lodash’s isEmpty, it’s crucial to understand what it actually checks for. At its core, _.isEmpty(value) determines if the value has no enumerable own properties. This means it’s not simply checking for falsiness or the absence of a value; it’s inspecting the “emptiness” in terms of content.

For objects, this means it looks for own enumerable properties. If there are none, it returns true. For arrays and strings, it checks the length property. If length is zero, it returns true. For other types like Maps and Sets, it checks their size.

Here’s a quick example:

console.log(_.isEmpty({}));          // true, no own properties
console.log(_.isEmpty({ a: 1 }));    // false, has a property 'a'
console.log(_.isEmpty([]));          // true, length is 0
console.log(_.isEmpty([1, 2, 3]));   // false, length is 3
console.log(_.isEmpty(''));          // true, empty string
console.log(_.isEmpty('abc'));       // false, length is 3

Notice that _.isEmpty returns true for null and undefined as well, because these don’t have enumerable properties or a length. That’s often convenient but can sometimes lead to surprises if you’re not expecting it.

It’s important to highlight that numbers and booleans are considered empty because they don’t have enumerable properties, despite being primitive values:

console.log(_.isEmpty(123));     // true
console.log(_.isEmpty(false));   // true

This behavior can feel counterintuitive. The function is not testing whether the value is “falsy,” but whether it has content you can iterate over or inspect.

Another edge case is functions. Functions don’t have enumerable own properties by default, so _.isEmpty(function() {}) returns true. If you attach properties to a function, _.isEmpty will reflect that:

function fn() {}
console.log(_.isEmpty(fn));    // true
fn.prop = 'value';
console.log(_.isEmpty(fn));    // false

This subtlety can be useful when you’re dealing with objects that might dynamically get properties added or removed but also can be a gotcha if you’re not careful.

Maps and Sets are handled by checking their size property:

const map = new Map();
console.log(_.isEmpty(map));      // true
map.set('key', 'value');
console.log(_.isEmpty(map));      // false

const set = new Set();
console.log(_.isEmpty(set));      // true
set.add(1);
console.log(_.isEmpty(set));      // false

Understanding these distinctions is key to using _.isEmpty effectively. It’s a tool for structural emptiness, not falsiness or nullity. When you want to know if something is structurally void of content, _.isEmpty is your friend.

But if you’re looking for “absence of a value” in a broader sense, you might need to combine checks or ponder what “empty” means in your particular context. For example, an empty string is empty, but the string "0" is not, even though both are truthy and falsy in different ways.

One last note: _.isEmpty does not deep check. It only looks at the immediate level. An object with a property whose value is an empty object is not empty itself:

console.log(_.isEmpty({ nested: {} }));  // false
console.log(_.isEmpty({ nested: [] }));  // false

So if you really want to know if an object or array is empty at every level, you’ll have to write a custom recursive check. But for most practical purposes, lodash’s isEmpty is a simple and efficient check for the presence or absence of top-level enumerable content.

Common pitfalls when checking for empty values with lodash

A common pitfall when using _.isEmpty is expecting it to behave like a falsy check or to treat certain primitives differently. For instance, 0, false, and NaN are all considered empty by _.isEmpty, which can be surprising if you’re using it to gate logic based on value presence.

console.log(_.isEmpty(0));      // true
console.log(_.isEmpty(false));  // true
console.log(_.isEmpty(NaN));    // true

Because these are primitive values without enumerable properties or length, _.isEmpty treats them as empty. If your intent is to check for “no meaningful value,” you’ll need to combine _.isEmpty with other checks:

function isValuePresent(val) {
  return val !== null && val !== undefined && !_.isEmpty(val);
}

console.log(isValuePresent(0));      // true, 0 is a meaningful value here
console.log(isValuePresent(false));  // true
console.log(isValuePresent(''));     // false, empty string is empty
console.log(isValuePresent([]));     // false, empty array is empty

Another gotcha arises when checking arrays or objects that might have properties set to undefined. _.isEmpty only checks for the presence of enumerable properties, not their values. So an object like { key: undefined } is considered non-empty because it has a property, even though the value is undefined:

console.log(_.isEmpty({ key: undefined }));  // false, property exists
console.log(_.isEmpty({}));                   // true, no properties

This means you can’t rely on _.isEmpty alone to check if all properties have meaningful values. For that, you’d need to iterate and check values explicitly:

function isObjectValuesEmpty(obj) {
  if (_.isEmpty(obj)) return true;
  return Object.values(obj).every(val => val === undefined || val === null);
}

console.log(isObjectValuesEmpty({ key: undefined }));  // true
console.log(isObjectValuesEmpty({ key: null }));       // true
console.log(isObjectValuesEmpty({ key: 0 }));          // false

Beware also when using _.isEmpty on strings that contain only whitespace. Since _.isEmpty checks length, a string of spaces is considered non-empty, even though it may be functionally “empty” in your application:

console.log(_.isEmpty('   '));  // false, length is 3

If you want to treat whitespace-only strings as empty, you’ll need to trim before checking:

function isStringEmptyOrWhitespace(str) {
  return _.isEmpty(str.trim());
}

console.log(isStringEmptyOrWhitespace('   '));  // true
console.log(isStringEmptyOrWhitespace('abc'));  // false

Finally, remember that _.isEmpty does not think inherited properties. It only checks own enumerable properties on objects. This can cause confusion when working with prototypes or instances of classes:

function MyClass() {}
MyClass.prototype.prop = 'value';

const instance = new MyClass();
console.log(_.isEmpty(instance));  // true, no own properties

instance.ownProp = 123;
console.log(_.isEmpty(instance));  // false, has own property 'ownProp'

If you want to detect inherited properties, _.isEmpty won’t help directly, and you’ll need to use other means such as for...in loops or Object.keys combined with hasOwnProperty.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *