JavaScript, elegant way to check nested object properties for null/undefined

A common problem that arises in JavaScript is the need to check whether nested object properties are null or undefined. This becomes especially cumbersome when dealing with large objects or multiple levels of nesting. In this article, we will explore various approaches to handle this issue in an elegant and efficient manner.

Understanding the Problem

Let's start by understanding the problem at hand. Suppose we have an object called user, which gets populated with data over time:


let user = {};
user.loc = {
    lat: 50,
    long: 9
};

At a later point in the code, we want to check whether the property user.loc.lat exists and is not null or undefined. The naive way to perform this check would be:


if (user.loc) {
    if (user.loc.lat) {
        // do something
    }
}

However, as the object's nesting becomes deeper and more complex, the code becomes increasingly cumbersome and difficult to read. It would be ideal to have a more elegant solution to address this issue. Let's explore a few options.

Using the Optional Chaining Operator

In modern versions of JavaScript, you can use the optional chaining operator (?.) to simplify the check for nested object properties. This operator allows you to access nested properties without throwing an error if any of the intermediate properties are null or undefined. Here's an example:


if (user?.loc?.lat) {
    // do something
}

In this case, if user.loc.lat is null or undefined, the expression will evaluate to false and the code block inside the if statement will not be executed.

It's important to note that the optional chaining operator is a relatively new addition to JavaScript and may not be supported by all browsers or environments. Make sure to check the compatibility before using it in production code, or consider transpiling your code using a tool like Babel to ensure broader compatibility.

Using the Lodash Library

If you prefer to use a popular utility library like Lodash, you can leverage its get function to perform the nested property check. The get function allows you to safely access properties of nested objects by providing a default value in case any of the intermediate properties are null or undefined. Here's an example:


if (_.get(user, 'loc.lat')) {
    // do something
}

In this case, if user.loc.lat is null or undefined, the _.get function will return undefined, which will evaluate to false in the if statement.

Keep in mind that using a utility library like Lodash might introduce additional overhead and increase the size of your JavaScript bundle. Consider the trade-off between convenience and performance when deciding whether to include such a library in your project.

Using a Custom Utility Function

If you prefer not to rely on external libraries, you can create a custom utility function to handle the nested property check. Here's an example:


function checkNested(obj, ...props) {
    for (let prop of props) {
        if (!obj || !obj.hasOwnProperty(prop)) {
            return false;
        }
        obj = obj[prop];
    }
    return true;
}

if (checkNested(user, 'loc', 'lat')) {
    // do something
}

In this example, the checkNested function recursively checks each property in the list of props against the obj object. If any of the properties is null or undefined, or if the property doesn't exist, the function returns false. Otherwise, it returns true.

You can customize the checkNested function to suit your specific needs. For example, you can modify it to accept the object as a method argument or define it as a utility method on the object prototype.

Conclusion

In this article, we explored different approaches to check for nested object properties in JavaScript. Whether you choose to use the optional chaining operator, a utility library like Lodash, or a custom utility function, it's important to handle the case where intermediate properties may be null or undefined. By employing these techniques, you can write more concise and readable code, especially when dealing with large and complex objects.