Using Underscore/Lodash: Yea or Nay?

twitter logo github logo ・1 min read

Underscore and Lodash (and similar libraries) are well documented and tested libraries that offer many useful functions not included in native JavaScript. There seems to be some varying thoughts on performance impacts and on their usage in general. What is your stance on the usage of these utility libraries? Are there any drawbacks to using it all the time?

twitter logo DISCUSS (7)
markdown guide
 

Here's my take. It's certainly true that many of the functions that made underscore and lodash so popular have been added to the language proper, and it's generally better for performance to use the native version of a function, which the browser can usually optimize more heavily, than to use a JS implementation of the same thing. And it's also certainly true that a smaller JS bundle size is faster to download, so fewer libraries can help there.

But with that said, lodash in particular is one of the most performant libraries out there. John-David Dalton, its creator and maintainer, is known for being a performance fiend. Heck, he's also the guy who created jsperf.com, everyone's favorite "run this code a billion times" app.

And as far as bundle size goes, lodash (and many other libraries) have moved in recent years to a very modularized format, which makes it very easy for build tools like webpack and parcel to do tree-shaking, removing at build-time any functions that are never used, which really helps reduce your bundle size.

If you do go with lodash (which I personally use all the time), I highly recommend looking into the lodash/fp module, which is amazing. It helps eliminate some of the biggest frustrations I've had with lodash in the past, and allows for much more streamlined code.

 

First, lets set some context. Lodash and Underscore come from a time where the JavaScript standard library lacked a lot of typical functions for array manipulation. JavaScript has since added a lot of these functions, and the result can be much more readable than Lodash. When you chain actions in Lodash, it can look a lot like this:

_.map(
    _.filter(
        _.map([1, 2, 3, 4], x => x * x),
        x => x % 2 === 0)
    x => String(x))

This is just difficult to read. To understand the control flow, you have to read these five lines in the order 3, 2, 4, 1, 5. Yeah you could condense some of those lines, but that just results in needing to skip to different places in the same line. Lets compare it with native JavaScript functions:

[1, 2, 3, 4]
    .map(x => x * x)
    .filter(x => x % 2 === 0)
    .map(x => String(x))

Much better. The control flow is obvious and easier to understand. Now it is true that there are some Lodash functions that JavaScript doesn't have natively. If you find yourself needing those functions, I'd recommend a more modern utility library like rambda. Ramdba has the pipe function that can keep the control flow apparent:

R.pipe(
  R.map(x => x * x),
  R.filter(x => x % 2 === 0),
  R.map(x => String(x))
)([1, 2, 3, 4])

This still has some overhead over the native JavaScript, but again, the rambda library contains a lot of functions that JavaScript still lacks.

 

Lodash actually has two different ways to do that same thing. Basic lodash has the chain object:

_([1,2,3,4])
    .map(x => x*x)
    .filter(x => x % 2 == 0)
    .map(x => String(x))
    .value()

And then there's the more recent (or modern, if you prefer) lodash/fp module, which looks a lot a like ramda:

fp.pipe(
    fp.map(x => x*x),
    fp.filter(x => x % 2 == 0),
    fp.map(x => String(x))
)([1,2,3,4])

I've heard good things about ramda as well, don't get me wrong, but it's worth knowing all your options fully ☺

And as a side note, I don't know if it makes sense to call ramda "more modern" than lodash; it's been around in some form since late 2013, around a year and a half after lodash came on the scene. IMHO, lodash is one of the most reliable, stable, best maintained projects out there. It's continually improving and being refined, as seen in the fp module. I wouldn't be too quick to dismiss it as outdated just yet

 

Yikes, didn't realize lodash already supported all of that! I did a quick search through the documentation, but didn't see that functionality listed 😬 my bad, thanks for setting the record straight!

Yeah tbh it's slightly hidden in the documentation itself, but the relevant documentation is here. There's a big paragraph there that discusses the difference between _(foo) and _.chain(foo), but the main point is you get an object that lets you chain the usual lodash methods and call .value() when you want the final result.

The basic difference between those two is that _(foo) expects an array or an object, and will automatically drop out of the chain and return the final result value as soon as you call a method that's not guaranteed to return an object or array. So if you call _(foo).map().filter().sortBy(), you'll need .value() at the end, but if you add a .get() or a .reduce(), it will return the value immediately, which can be nice. _.chain(foo) will never drop out of the chain object, you always need to call .value(), which is also helpful sometimes.

 

Thank you for the concise explanation and examples! I had used Lodash (and was encouraged to do so whenever possible) in the past for work, and I wondered if this was relatively common in other workplaces.

 

I use lodash when I'm in need of some specific functions, js language doesn't provide itself.

My opinion is if you need some of it, just use it, there won't be any visible performance hit.

Just remember to import only specific functions you need, not whole lib which can be pretty big.

Classic DEV Post from Sep 9 '18

Small bits of web UX

I'm not sure how to call those. This good tone for web experience

Brian Pak profile image
curious learner