Differences between Lodash and Underscore.js [closed]
Asked Answered
E

12

1722

Why would someone prefer either the Lodash or Underscore.js utility library over the other?

Lodash seems to be a drop-in replacement for underscore, the latter having been around longer.

I think both are brilliant, but I do not know enough about how they work to make an educated comparison, and I would like to know more about the differences.

Exstipulate answered 9/12, 2012 at 17:8 Comment(4)
You might want to take a look at some of the screen-casts about lodash that are linked to on its github page. Personally I've been using underscore.js, but more because that's what I started with and as you say its been around longer.Justinn
lodash and underscore are under merge thread nowFrondescence
FYI: The Underscore & Lodash scratch padAmpliate
lodash is more widely downloaded, 50M vs 10M as of 2023.Hepsiba
S
2161

I created Lodash to provide more consistent cross-environment iteration support for arrays, strings, objects, and arguments objects1. It has since become a superset of Underscore.js, providing more consistent API behavior, more features (like AMD support, deep clone, and deep merge), more thorough documentation and unit tests (tests which run in Node.js, RingoJS, Rhino, Narwhal, PhantomJS, and browsers), better overall performance and optimizations for large arrays/object iteration, and more flexibility with custom builds and template pre-compilation utilities.

Because Lodash is updated more frequently than Underscore.js, a lodash underscore build is provided to ensure compatibility with the latest stable version of Underscore.js.

At one point I was even given push access to Underscore.js, in part because Lodash is responsible for raising more than 30 issues; landing bug fixes, new features, and performance gains in Underscore.js v1.4.x+.

In addition, there are at least three Backbone.js boilerplates that include Lodash by default and Lodash is now mentioned in Backbone.js’s official documentation.

Check out Kit Cambridge's post, Say "Hello" to Lo-Dash, for a deeper breakdown on the differences between Lodash and Underscore.js.

Footnotes:

  1. Underscore.js has inconsistent support for arrays, strings, objects, and arguments objects. In newer browsers, Underscore.js methods ignore holes in arrays, "Objects" methods iterate arguments objects, strings are treated as array-like, and methods correctly iterate functions (ignoring their "prototype" property) and objects (iterating shadowed properties like "toString" and "valueOf"), while in older browsers they will not. Also, Underscore.js methods, like _.clone, preserve holes in arrays, while others like _.flatten don't.
Senescent answered 16/12, 2012 at 5:34 Comment(23)
Thanks for the answer, John-David, your thoughts are much appreciated. Do you think that it is fair to say that lodash is effectively always preferable to underscore? (Better question: Can you think of anyone who would disagree with that assertion?) Many thanks.Exstipulate
@Brian - While developing Lo-Dash I've continued to ask the question "What could someone point to, in Lo-Dash, as a negative compared to Underscore?" and then address them. This is why I've beefed up documentation, added custom builds, & made the source more readable.Senescent
I am very tempted to post some benchmarks, but that could become tedious. Suffice to say that every benchmark I've run has proven Lo-Dash to be faster (MUCH faster in many cases) than underscore.Apuleius
Why does the backbone boilerplate contain paths to lodash and underscore. In my require.config({paths : {'underscore' : "_lib/lodash/v1.0.0-rc3/lodash-min"}Balustrade
@Shanimal: Backbone requires underscore. Instead of using underscore the boilerplate wants to use lodash as a replacement so it sets the 'underscore' path to point to your lodash location.Lighthouse
I love lo-dash and I am using it, so please don't think I am bashing, but why not contribute to underscore instead of creating a new library?Countdown
On my Firefox 19 under Mint underscore seems to be faster then lo-dash while running jsperf.com/lodash-underscore. But on Google Chrome 26 it is opposite. It is browser dependent as I see.Hollingsworth
@Countdown - check the comments thread: github.com/jashkenas/underscore/commit/… - this may answer that question.Bugleweed
@RobertGrant Looks like there's some emotion behind this: github.com/jashkenas/underscore/commit/… I see more lo-dash dependencies when running npm update than anything else. I've got to check this out.Basutoland
Additionally, I also found out that the _.union function for lodash and underscore differs in the way that underscore.union([], 3) === [3] and lodash.union([], 3) === []Schoolmarm
@KumarHarsh see github.com/jashkenas/underscore/pull/1317 next version of underscore should align with lodash on that issueProd
Has there been any effort to merge lodash back into underscore?Quadriplegia
Lo-Dash 3.0 will support Lazy Evaluation, while Underscore doesn't. Read more: filimanjaro.com/blog/2014/introducing-lazy-evaluationTzar
@streetlight: There is now (or is it the reverse?)Valletta
underdash planning is in progress!Hierodule
why not just patch on underscore XDParesis
Looking at the article cited -- Say "Hello"to Lo-Dash "“native-first dual approach.” This approach prefers native implementations, falling back to vanilla JavaScript only if the native equivalent is not supported." I am confused, what is the difference between native and vanilla JavasScript?Toratorah
@ClayMorton functions provided by the browser (native) vs functions that must be run by the js runtime (not native).Coffman
I heard that Ramda.js was better for pure functional programming?Eaton
@AlexMills lodash has that covered with lodash-fp.Senescent
There's one thing that in my eyes puts Underscore ahead of Lodash, even though everyone sees it quite the opposite: Underscore's landing page has documentation right there, with the search field, while for Lodash you need one additional step - to click the "documentation" link on the landing page which finally gets you where you wanna go. It's a minor thing, but when you do that on daily basis, it's a significant difference in time.Hestia
What is lodash equivalent of underscore.js "where"Glasshouse
@ßãlãjî filterEsquimau
A
202

Lodash is inspired by Underscore.js, but nowadays it is a superior solution. You can make your custom builds, have a higher performance, support AMD and have great extra features. Check this Lodash vs. Underscore.js benchmarks on jsperf and... this awesome post about Lodash:

One of the most useful features, when you work with collections, is the shorthand syntax:
(although Underscore now also supports this syntax)

var characters = [
  { 'name': 'barney', 'age': 36, 'blocked': false },
  { 'name': 'fred',   'age': 40, 'blocked': true }
];

// Using "_.filter" callback shorthand
_.filter(characters, { 'age': 36 });

// Using Underscore.js
_.filter(characters, character => character.age === 36);

// → [{ 'name': 'barney', 'age': 36, 'blocked': false }]

(taken from Lodash documentation)

Asarum answered 13/12, 2012 at 21:51 Comment(6)
The link to Kit Cambridge's blog is very informative.Exstipulate
I think this is wrong (the pluck example). As of the last update 1.8.3, you can use pluck the same way as lodash. anyway for previous versions I don't think underscore would expose a function that is the same a map (your underscore example seems like a map function)Pincenez
filter feature in underscore from 2012 github.com/jashkenas/underscore/issues/648 (its name is where)Pesade
I'm getting error 500 on the Lo-Dash vs Underscore benchmark linkConchiolin
characters.filter(x=>x.age==36) //pure jsSwordplay
@AlexSzücs avoid using x as variable name, character is preferible for being more descriptiveAsarum
N
112

If, like me, you were expecting a list of usage differences between Underscore.js and Lodash, there's a guide for migrating from Underscore.js to Lodash.

Here's the current state of it for posterity:

  • Underscore _.any is Lodash _.some
  • Underscore _.all is Lodash _.every
  • Underscore _.compose is Lodash _.flowRight
  • Underscore _.contains is Lodash _.includes
  • Underscore _.each doesn’t allow exiting by returning false
  • Underscore _.findWhere is Lodash _.find
  • Underscore _.flatten is deep by default while Lodash is shallow
  • Underscore _.groupBy supports an iteratee that is passed the parameters (value, index, originalArray), while in Lodash, the iteratee for _.groupBy is only passed a single parameter: (value).
  • Underscore.js _.indexOf with third parameter undefined is Lodash _.indexOf
  • Underscore.js _.indexOf with third parameter true is Lodash _.sortedIndexOf
  • Underscore _.indexBy is Lodash _.keyBy
  • Underscore _.invoke is Lodash _.invokeMap
  • Underscore _.mapObject is Lodash _.mapValues
  • Underscore _.max combines Lodash _.max & _.maxBy
  • Underscore _.min combines Lodash _.min & _.minBy
  • Underscore _.sample combines Lodash _.sample & _.sampleSize
  • Underscore _.object combines Lodash _.fromPairs and _.zipObject
  • Underscore _.omit by a predicate is Lodash _.omitBy
  • Underscore _.pairs is Lodash _.toPairs
  • Underscore _.pick by a predicate is Lodash _.pickBy
  • Underscore _.pluck is Lodash _.map
  • Underscore _.sortedIndex combines Lodash _.sortedIndex & _.sortedIndexOf
  • Underscore _.uniq by an iteratee is Lodash _.uniqBy
  • Underscore _.where is Lodash _.filter
  • Underscore _.isFinite doesn’t align with Number.isFinite
    (e.g. _.isFinite('1') returns true in Underscore.js, but false in Lodash)
  • Underscore _.matches shorthand doesn’t support deep comparisons
    (e.g., _.filter(objects, { 'a': { 'b': 'c' } }))
  • Underscore ≥ 1.7 & Lodash _.template syntax is
    _.template(string, option)(data)
  • Lodash _.memoize caches are Map like objects
  • Lodash doesn’t support a context argument for many methods in favor of _.bind
  • Lodash supports implicit chaining, lazy chaining, & shortcut fusion
  • Lodash split its overloaded _.head, _.last, _.rest, & _.initial out into
    _.take, _.takeRight, _.drop, & _.dropRight
    (i.e. _.head(array, 2) in Underscore.js is _.take(array, 2) in Lodash)
Nickelic answered 21/7, 2016 at 9:35 Comment(2)
I've come across these problems myself when migrating and I'm maintaining a (WIP) cross documentation going between one and the other. Hope it's helpful to other people as well!Bisulcate
Nice diff! ★★★★★Alena
S
60

In addition to John's answer, and reading up on Lodash (which I had hitherto regarded as a "me-too" to Underscore.js), and seeing the performance tests, reading the source-code, and blog posts, the few points which make Lodash much superior to Underscore.js are these:

  1. It's not about the speed, as it is about consistency of speed (?)

If you look into Underscore.js's source-code, you'll see in the first few lines that Underscore.js falls-back on the native implementations of many functions. Although in an ideal world, this would have been a better approach, if you look at some of the performance links given in these slides, it is not hard to draw the conclusion that the quality of those 'native implementations' vary a lot browser-to-browser. Firefox is damn fast in some of the functions, and in some Chrome dominates. (I imagine there would be some scenarios where Internet Explorer would dominate too). I believe that it's better to prefer a code whose performance is more consistent across browsers.

Do read the blog post earlier, and instead of believing it for its sake, judge for yourself by running the benchmarks. I am stunned right now, seeing a Lodash performing 100-150% faster than Underscore.js in even simple, native functions such as Array.every in Chrome!

  1. The extras in Lodash are also quite useful.
  2. As for Xananax's highly upvoted comment suggesting contribution to Underscore.js's code: It's always better to have GOOD competition, not only does it keep innovation going, but also drives you to keep yourself (or your library) in good shape.

Here is a list of differences between Lodash, and it's Underscore.js build is a drop-in replacement for your Underscore.js projects.

Schoolmarm answered 18/8, 2013 at 14:18 Comment(12)
In which case is "consistency of speed" a value? Let's say, I have a method that has a speed of 100% in FF and in IE and a native implementation would have a speed of 80% in IE and 120% in FF (or the other way round). Then I would say it would be good to use the native implementation in FF and the own implementation in IE. I cannot imagine any case, where I would say: Let's slow down FF just for the reason to have the same speed there as in IE. Size of code and maintainability or an average slowdown in all browsers would be arguments, but consistency of speed?Degeneracy
I meant, "consistently faster speed"Schoolmarm
A car going at 20kmph for a day won't be much use :)Schoolmarm
What about the difference in size? Let's say you create a custom build with lodash that has exactly the same functionality as underscore? Is there a big difference between them? I would guess reimplementation adds weight to the site.Stilla
underscore has a smaller footprint, because it mostly wraps over native functions.Schoolmarm
I'm inclined to fallback to browser's native implementation simply because in most cases it has acceptable performance and can improve with browser updates without worry to keep the library up to date.Antoneantonella
@Antoneantonella you may want to do a little bit more reading on that. In some cases native implementations do NOT have acceptable performance. Just saying...Richela
@orad: by all means you can, even I'm inclined to... But then comes the case of supporting IE8- in some cases, you there's nothing you can do really. Anyways, instead of blindly chucking out the library, have a look at the source code: in some cases, the lodash/underscore libs are just thinly wrapping native implementations.Schoolmarm
@KumarHarsh Maybe I didn't phrase it well. I meant I'm inclined to use a library that internally uses native functions if available, instead of always preferring its own implementation.Antoneantonella
@kumar_harsh We're talking about a car that can't do more than 60kmph vs a sportscar. You wouldn't know the difference in city driving anyway. If you're driving in the city most of the time, you don't really NEED a better car. City driving being most of your code in an average project.Diversification
OK, enough with the car comparisons :)... Bottom line is that as a developer, you can use whatever you want. When your environment is Nodejs or you have webpack in your build chain, Lodash is better, no questions asked. For a browser also lodash is better (the functions it provides are far more useful). If you really want to go with underscorejs for some reason, Lodash has a core build which is in fact smaller than underscore, although I don't know the size of it's underscore build.Schoolmarm
Plus, with webpack, for most of the functions nowadays, I just use the native implementations. [].map, etc are just fixed at compile time by babel if I choose to target ES5 browsers, so mostly I find myself using lodash for the features which are not in ES6, or not so easy to write, such as _.sortBy, etcSchoolmarm
C
44

In 2014 I still think my point holds:

IMHO, this discussion got blown out of proportion quite a bit. Quoting the aforementioned blog post:

Most JavaScript utility libraries, such as Underscore, Valentine, and wu, rely on the “native-first dual approach.” This approach prefers native implementations, falling back to vanilla JavaScript only if the native equivalent is not supported. But jsPerf revealed an interesting trend: the most efficient way to iterate over an array or array-like collection is to avoid the native implementations entirely, opting for simple loops instead.

As if "simple loops" and "vanilla Javascript" are more native than Array or Object method implementations. Jeez ...

It certainly would be nice to have a single source of truth, but there isn't. Even if you've been told otherwise, there is no Vanilla God, my dear. I'm sorry. The only assumption that really holds is that we are all writing JavaScript code that aims at performing well in all major browsers, knowing that all of them have different implementations of the same things. It's a bitch to cope with, to put it mildly. But that's the premise, whether you like it or not.

Maybe all of you are working on large scale projects that need twitterish performance so that you really see the difference between 850,000 (Underscore.js) vs. 2,500,000 (Lodash) iterations over a list per second right now!

I for one am not. I mean, I worked on projects where I had to address performance issues, but they were never solved or caused by neither Underscore.js nor Lodash. And unless I get hold of the real differences in implementation and performance (we're talking C++ right now) of, let’s say, a loop over an iterable (object or array, sparse or not!), I rather don't get bothered with any claims based on the results of a benchmark platform that is already opinionated.

It only needs one single update of, let’s say, Rhino to set its Array method implementations on fire in a fashion that not a single "medieval loop methods perform better and forever and whatnot" priest can argue his/her way around the simple fact that all of a sudden array methods in Firefox are much faster than his/her opinionated brainfuck. Man, you just can't cheat your runtime environment by cheating your runtime environment! Think about that when promoting ...

your utility belt

... next time.

So to keep it relevant:

  • Use Underscore.js if you're into convenience without sacrificing native'ish.
  • Use Lodash if you're into convenience and like its extended feature catalogue (deep copy, etc.) and if you're in desperate need of instant performance and most importantly don't mind settling for an alternative as soon as native API's outshine opinionated workarounds. Which is going to happen soon. Period.
  • There's even a third solution. DIY! Know your environments. Know about inconsistencies. Read their (John-David's and Jeremy's) code. Don't use this or that without being able to explain why a consistency/compatibility layer is really needed and enhances your workflow or improves the performance of your application. It is very likely that your requirements are satisfied with a simple polyfill that you're perfectly able to write yourself. Both libraries are just plain vanilla with a little bit of sugar. They both just fight over who's serving the sweetest pie. But believe me, in the end both are only cooking with water. There's no Vanilla God so there can't be no Vanilla pope, right?

Choose whatever approach fits your needs the most. As usual. I'd prefer fallbacks on actual implementations over opinionated runtime cheats anytime, but even that seems to be a matter of taste nowadays. Stick to quality resources like http://developer.mozilla.com and http://caniuse.com and you'll be just fine.

Cloudscape answered 11/9, 2014 at 21:27 Comment(11)
Thanks for posting Lukas. Can the built-ins can be further optimized? I gathered they have constraints imposed by the standards that prevent them from having optimizations comparable to the libraries, but I do not know the details offhand or whether this was or remains true.Exstipulate
e.g. "By optimising for the 99% use case, fast.js methods can be up to 5x faster than their native equivalents." – github.com/codemix/fast.jsExstipulate
Hi Brian, I'm sorry if this was misleading, I didn't mean to say that those libraries are not much faster than their native equivalents. If you're in desperate need of performance right now, you're probably better off with a toolkit like LoDash or fast.js as they do provide faster implementations of standard methods. But if you choose to use a library that does not fall back on native methods you may just miss out on any future performance optimisations on built-ins. Browsers will evolve eventually.Placement
Thanks Lukas. I guess if the browsers eventually deviate from or evolve the Javascript standard then it may be possible for them to reach (and exceed, as you say) the performance of the libraries. I suspect this is a long way off, but who knows. One can hope. :) CheersExstipulate
jsperf.com/native-vs-array-js-vs-underscore/37. At least in this case, it's either for-loops or Array.map that wins the match.Placement
Just for the record: The Javascript / ECMA standards or specs are merely descriptive in terms of function signature et al and impose no rules or guidelines whatsoever as far as implementation is concerned. "The standards" have nothing to do with performance.Placement
Browser "manufacturers" have a hard time keeping their browsers standards compliant, much less performant. Most performance gains in native implementations are a result of faster hardware. The "native implementations will catch up" excuse has been around for years. Years = eternity on the internet. IF native implementations ever catch up, the libraries will be updated to use them. That's the cool thing about open source. If an app dev does not update to the latest library, their app won't suddenly slow down, it just won't speed up.Richela
Andrew, thanks for sharing your thoughts on this. Whether or not browser manufacturers care about performance or not is beyond my knowledge, to be honest. But I do know that one doesn't contribute to any resolution of the standard compliance issue by inventing "utility belts" that don't even seem to care about standard function signature conventions. Half of the JS devs out there probably could recite the signature of $.each and _.forEach (including the callback=_.identity convention, which in fact encourages people to not even providing callbacks at all) even after a couple of pitchers...Placement
... but if you asked them about Array.from they'd probably wouldn't even know what it is supposed to do. The JS "utility belt" people seem to be so overly concerned with promoting their oh-so-genial workarounds that they tend to forget that by doing so, they are actually diluting the standardization process. No need of features leads to no pressure on browser "manufacturers". Fun fact: 2 of the 4 major browsers are based on open source projects (1, 2).Placement
Good point about lodash's deepCopy. I keep wishing I had that when working in underscore-based projects.Southwesterly
For your final point (DIY), there is a website (You Might Not Need - Lodash) that shows a plain ES6 approach for most Lodash functions.Alena
D
27

I'm agree with most of things said here, but I just want to point out an argument in favor of Underscore.js: the size of the library.

Specially in case you are developing an app or website which intend to be use mostly on mobile devices, the size of the resulting bundle and the effect on the boot or download time may have an important role.

For comparison, these sizes are those I noticed with source-map-explorer after running Ionic serve:

Lodash: 523 kB
Underscore.js: 51.6 kB

One can use BundlePhobia to check the current size of Lodash and Underscore.js.

Dextran answered 26/4, 2017 at 14:20 Comment(5)
Thanks Peter, this is a worthwhile point to note here. There's more discussion elsewhere, including: gist.github.com/alekseykulikov/5f4a6ca69e7b4ebed726 . (This answer could be improved by linking some of the other discussions and quoting the relevant bits) The difference in size can be reduced by choosing subsections of lodash, plus tree-shaking lodash. 🕷Exstipulate
Thx @BrianM.Hunt for your reply, didn't know that it's possible to include subsections of lodash, gonna have a look. Recently with ionic-native, Ionic took such a path too for their native libs, good to note that more an more are concerned about app sizeDextran
i wonder where did you get the 523kB? lodash.com says it's only 24kB compressed. downloaded is only 74kBLoxodromics
my post was made in april 2017. like I said in my comment, source-map-explorer after running ionic serveDextran
In March 2018 - lodash.min.js is 72,5 kB and underscore-min.js is 16,4 kBAlathia
H
11

I am not sure if that is what OP meant, but I came across this question because I was searching for a list of issues I have to keep in mind when migrating from Underscore.js to Lodash.

I would really appreciate if someone posted an article with a complete list of such differences. Let me start with the things I've learned the hard way (that is, things which made my code explode on production:/):

  • _.flatten in Underscore.js is deep by default, and you have to pass true as second argument to make it shallow. In Lodash it is shallow by default and passing true as second argument will make it deep! :)
  • _.last in Underscore.js accepts a second argument which tells how many elements you want. In Lodash there is no such option. You can emulate this with .slice
  • _.first (same issue)
  • _.template in Underscore.js can be used in many ways, one of which is providing the template string and data and getting HTML back (or at least that's how it worked some time ago). In Lodash you receive a function which you should then feed with the data.
  • _(something).map(foo) works in Underscore.js, but in Lodash I had to rewrite it to _.map(something,foo). Perhaps that was just a TypeScript-issue.
Hoard answered 25/3, 2015 at 12:16 Comment(2)
In lodash, chaining passes a lazy iterator, and requires and endpoint like _(something).map(foo).value().Exstipulate
This all can hit you if you use Backbone Collection which proxies calls to these libraries - for example collection.first(5) will not give you the first 5 elements, but rather the first one :)Hoard
S
9

Underscore vs Lo-Dash by Ben McCormick is the latest article comparing the two:

  1. Lodash's API is a superset of Underscore.js's.
  1. Under the hood, Lodash has been completely rewritten.
  1. Lodash is definitely not slower than Underscore.js.
  1. What has Lodash added?
  • Usability improvements
  • Extra functionality
  • Performance gains
  • Shorthand syntaxes for chaining
  • Custom builds to only use what you need
  • Semantic versioning and 100% code coverage
Shorthanded answered 7/12, 2014 at 12:19 Comment(0)
A
6

I just found one difference that ended up being important for me. The non-Underscore.js-compatible version of Lodash's _.extend() does not copy over class-level-defined properties or methods.

I've created a Jasmine test in CoffeeScript that demonstrates this:

https://gist.github.com/softcraft-development/1c3964402b099893bd61

Fortunately, lodash.underscore.js preserves Underscore.js's behaviour of copying everything, which for my situation was the desired behaviour.

Amanda answered 12/12, 2014 at 16:56 Comment(0)
I
4

Lodash has got _.mapValues() which is identical to Underscore.js's _.mapObject().

Incident answered 18/7, 2015 at 17:13 Comment(0)
R
0

For the most part Underscore.js is subset of Lodash.

At times, like presently, Underscore.js will have cool little functions Lodash doesn't have, like mapObject. This one saved me a lot of time in the development of my project.

Rodgerrodgers answered 14/5, 2015 at 11:16 Comment(2)
at the time, we have _.mapValuesElectrodialysis
@Electrodialysis - at the time of this post I knew of mayValues and mapKeys but they're not the same as mapObject. Maybe there are cases to apply one over the other but mapObject is a function all its own.Rodgerrodgers
S
0

They are pretty similar, with Lodash is taking over...

They both are a utility library which takes the world of utility in JavaScript...

It seems Lodash is getting updated more regularly now, so more used in the latest projects...

Also Lodash seems is lighter by a couple of KBs...

Both have a good API and documentation, but I think the Lodash one is better...

Here is a screenshot for each of the documentation items for getting the first value of an array...

Underscore.js:

Underscore.js

Lodash:

Lodash

As things may get updated time to time, just check their website also...

Lodash

Underscore.js

Sepal answered 19/1, 2019 at 6:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.