15

How does Lodash compare to using the new ES6 optional arguments?

I have the following code:

location: {
  latitude: response.pickupLocation.latitude || "",
  longitude: response.pickupLocation.longitude || ""
},

With Lodash I know I could run:

latitude: get(response, 'pickupLocation.latitude', '')

Or alternatively I could create a function that takes in the object and path and always returns ''as the default fallback. Is there any advantage to using Lodash here other than the fact that the code would be shorter?

abrarisme
  • 495
  • 1
  • 6
  • 14
  • You mean `location: (({latitude = "", longitude = ""}) => ({latitude, longitude}))(response.pickupLocation)`? Or maybe just `location: Object.assign({latitude: "", longitude: ""}, response.pickupLocation)`. – Bergi Aug 22 '17 at 07:57

4 Answers4

22

The advantage of _.get is, you omit continuing checks if a property exist, which would be necessary.

latitude: response && response.pickupLocation && response.pickupLocation.latitude || "",
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
11

For the latest browsers, or by using polyfills or transpiler, you could also use optional chaining and nullish coalescing operator like:

latitude: response?.pickupLocation?.latitude ?? ''
Samyak Lal
  • 111
  • 1
  • 4
6

This has nothing to do with ES6, it is just the logical OR operator. "Optional arguments" sounds like you are relating to default parameters but these are used in function signatures.

Personally, I would stick with the logical OR as it does not require an external library. Also I would recommend to never use strings when you want to access object properties because it complicates refactoring, usage search, the optional use of TypeScript, and hinders code completion.

If you want to make sure, that no exception occurs when you access a property of a null type, you can use the approach described here:

getSafe(() => response.pickupLocation.latitude) || ''
str
  • 42,689
  • 17
  • 109
  • 127
2

Referring to @str's answer, if response does not have a pickupLocation property, this will result in a TypeError (Cannot read property latitude of undefined), regardless of the OR operator.

You could wrap this in a try-catch. Then you would return response.pickupLocation.latitude || fallback in try or fallback in a catch block.

This will not handle the defined by falsey values (imagine that response.pickupLocation.latitude is 0). This function will return a fallback value, not 0. This can be handled easily by checking typeof (typeof response.pickupLocation.latitude !== 'undefined' ? response.pickupLocation.latitude : fallback), however we are still talking about a hardcoded object path. The same issue is presented on the accepted answer as well.

To handle this dynamically for any object path, you have to loop over a provided object, check for hasOwnProperty and peel off the nested properties by each iteration until you get to end of the specified path. Something like this:

const getSafe = (object, path, fallback) => {
    const fragments = path.split('.')
    let value

    for (let i = 0; i < fragments.length; i++) {
        if (!obj.hasOwnProperty(fragments[i])) {
            return fallback;
        }
        value = object[fragments[i]];
    }

    return value;
}
Van G
  • 21
  • 3
  • "*Referring to @str's answer, if response does not have a pickupLocation property, this will result in a TypeError*"–No it won't. That is the whole point of using a `getSafe` function. – str Aug 03 '20 at 09:14