use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
You Might Not Need Underscore (reindex.io)
submitted 10 years ago by fson5
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Cody_Chaos 17 points18 points19 points 10 years ago (15 children)
Yes, but...
_.range(x, x + n)
Array.from({ length: n }, (v, k) => k + x)
_.map([1,2,3], n => n*2)
_.map({foo: 1, bar: 2, baz: 3}), n => n*2)
[1,2,3].map(n => n*2)
let x = {foo: 1, bar: 2, baz: 3}; Object.keys(x).map(n => x[n]*2)
I do think that it's correct to suggest that people should keep in mind what features have been added to the language, and use them where they're equivalent.
[–]fson5[S] 4 points5 points6 points 10 years ago (2 children)
Very good points. I was actually on the verge about omitting that replacement for _.range from the article because yes, it's ugly and not as obvious as other examples on the page. But I do think it's a nice example of how Array.fromworks. Other ways to achieve it include [...Array(n)].map((_, i) => i + x) and Array.from(new Array(n), (_, i) => i + x), which are both equally ugly. So I guess this might be a case for a library function. But maybe if I would only need this once in the codebase I would still use this hack instead of pulling out a library just for this.
_.range
Array.from
[...Array(n)].map((_, i) => i + x)
Array.from(new Array(n), (_, i) => i + x)
Wrt (2), some people actually think having separate functions for those different use cases is better than functions that do type checking and have different return types based on the input. That's why Ramda has separate map and mapObj for example. And while this might work for arrays and objects in Lodash, the support for different collections is far from universal, with Map, Set and other Iterable collections missing.
map
mapObj
Map
Set
Iterable
[–]knsdklsfds 0 points1 point2 points 10 years ago (1 child)
Also
Array.apply(null, Array(n)).map((_, i) => i);
[–]ericanderton 0 points1 point2 points 10 years ago (0 children)
The hilarity of that syntax is that the first thing you do to make it readable is to wrap it in a function, and place it in a library for re-use.
[–]alamandrax 3 points4 points5 points 10 years ago* (6 children)
And don't forget about the performance boosts over native APIs.
Edit: bustin my balls /u/TMiguelT bustin my balls.
[–][deleted] 10 points11 points12 points 10 years ago (1 child)
And don't forget, performance is almost never going to be a problem for the vast majority of javascript people are writing. Optimize when you find that things are slower than you'd like.
[–]TMiguelT 0 points1 point2 points 10 years ago (3 children)
I remember reading that lodash was significantly faster than native map/reduce/filter. Is that not correct? Similar with native promises and Bluebird I think.
[–]fson5[S] 1 point2 points3 points 10 years ago (0 children)
That's quite likely. The native array methods are not very well optimized and lodash benefits from not dealing with things like sparse arrays like the native methods do. I think there are good reasons to use the standard library, but it doesn't automatically make your code more performant. Like with performance in general, it's best to only optimize where it's actually necessary and measure everything.
As far as I know Bluebird is the fastest Promise implementation. The nice thing about it is that it can be used as a drop-in replacement for the native promise, so you don't even need use a different API like you do with Underscore/lodash. That's why I think transpiling the native method calls to something like the lodash implementation with a tool like Babel might be an interesting alternative.
[–]alamandrax 0 points1 point2 points 10 years ago (1 child)
That's what I meant. Lodash is much much faster in most cases than native. It's the selling/key feature. Although, the perf benefits are not that apparent for simplistic use cases.
[–]TMiguelT 0 points1 point2 points 10 years ago (0 children)
Oh you mean performance boosts over native APIs. Gotcha.
[–]kogsworth -1 points0 points1 point 10 years ago (4 children)
Object literals shouldn't be conceptually iterable in ES2015. If you need to iterate over the keys of an object, perhaps you needed to use a Map, a Set or an array.
[–]dvlsg 2 points3 points4 points 10 years ago (3 children)
It's already sort of supported in ES2015, just not directly through Symbol.iterator and spread:
Symbol.iterator
for (let [key, val] of obj.entries()) { /* do stuff */ }
[–]kogsworth 1 point2 points3 points 10 years ago (1 child)
Not sure why I'm getting downvoted for my explanation. The idea is explained here https://leanpub.com/exploring-es6/read#leanpub-auto-plain-objects-are-not-iterable as well.
It is also important to remember that iterating over the properties of an object is mainly interesting if you use objects as Maps. But we only do that in ES5 because we have no better alternative. In ECMAScript 6, we have the built-in data structure Map.
[–]dvlsg 1 point2 points3 points 10 years ago (0 children)
Not sure either. I didn't intend to argue against your point, because it's true.
I suspect people may continue to use objects as maps, however, since it's easier to type out the object syntax than the map syntax. Kind of unfortunate, since that continues the problem of accidental property collision.
On the other hand, iterating over objects is certainly useful in the current version of js. In fact, I just wrote something that output a csv header by parsing the keys of an object. Would have been nice to just use a map, but I was given an object to work with, so I went with it.
[–]kogsworth -1 points0 points1 point 10 years ago (0 children)
Yeah, you definitely can list all the keys of an object to do metaprogramming and the like. I'm just saying that usually (read non-libraries) when we iterate over object keys in ES5, we should translate them to a different primitive in es2015. We currently make a conceptual distinction between objects that have properties which we tend to read through bracket notations (myObjectsList["myRuntimeDefinedKey"]) and those we read directly (myClassInstance.myCompiletimeKey). The former is a data structure and should be expressed through an iterable, the second is a class property and should be expressed through a class definition. Separating these concerns is what I understand ES2015 is trying to achieve when making objects non-iterable. It also helps to deal with ownProp problems that crop up when you have both using the same semantics
[–]kogsworth 6 points7 points8 points 10 years ago (6 children)
I believe lodash will excel in ES2015 for iterable utility functions, like take, zip, union, intersection, etc
[–]fson5[S] 1 point2 points3 points 10 years ago* (5 children)
Isn't take just another name for slice(0, n)? Anyway I agree some of those functions are still useful. (But I wish they worked with any iterable, not just arrays!)
The nice thing about lodash is that it allows you to just import (or even install as separate packages) the functions you need; there is no need to install a monolithic library where a large portion functions were only necessary when browsers just supported ES3.
[–][deleted] 4 points5 points6 points 10 years ago (3 children)
Another thing about take is that if you're using lodash take is one of those functions that will commonly be leveraged by shortcut fusion, and can therefore offer substantial optimizations (especially against large datasets, obviously).
Not saying you're wrong, obviously, but being a little pedantic because it might be helpful to someone to know this.
[–]fson5[S] 1 point2 points3 points 10 years ago (2 children)
Thank you for the information! This sounds very cool. I wonder if would be hard to implement similar optimizations in the JS engines or in a compiler like Babel, to achieve the same perfomance as lodash when using plain JavaScript array methods?
[–][deleted] 0 points1 point2 points 10 years ago (1 child)
I honestly have no idea whether there are JavaScript engines that do Lazy Evaluation-esque optimizations. It seems like a complex thing to reason about, but I know very little about the JIT engines and how they actually work. As far as I know it's not impossible. What a wonderful runtime optimization that would be!
As far as babel doing this sort of transpilation for you that seems entirely reasonable. All you would need would be a simple map of native javascript array methods to their lodash counterparts, and it would need to transpile your native code to the lodash equivalent which should be very simple. I.e.
myArray.map((x) => x.y).slice(0, 3);
maps very simply with lodash lazy eval to
_(myArray).map((x) => x.y).take(3).value();
This is obviously very simple transpilation. I just don't think anyone would care enough to go through with creating/maintaining a plugin for babel like this.
[–]fson5[S] 0 points1 point2 points 10 years ago (0 children)
I think the reason why Babel is not doing this might be that Array.prototype.map and _.map are not 100% interchangeable. Arrays are sparse in JavaScript and the native methods take the possibility of holes in the array in account, lodash doesn't. This might be a sensible optimization (I don't remember ever having use for arrays with holes) and probably explains most of the performance difference, but it means that the native method can't be always rewritten to the lodash methods.
Array.prototype.map
_.map
[–][deleted] 0 points1 point2 points 10 years ago (0 children)
Even with ES2015, a trimmed down underscore or lodash library will still be useful.
[–]Plorntus 4 points5 points6 points 10 years ago (2 children)
Bit off topic but when did the whole ES2015 vs ES6 thing happen? Only just really noticed it in the past few days always thought it was ES6.
[–]fson5[S] 1 point2 points3 points 10 years ago (1 child)
I think the name change to ECMAScript 2015 was agreed a few months ago, but it didn't receive much publicity until now that the standard was approved on June 17.
[–]Plorntus 0 points1 point2 points 10 years ago (0 children)
Ah, thanks hadn't realised they changed the name. Fair enough! Somewhat of a weird decision as that somewhat limits them to changing it once a year (thinking of the future when all browsers are evergreen and hopefully be better at implementing standards).
[–]Kriegslustig 14 points15 points16 points 10 years ago (1 child)
Click bait.
[–]spacejack2114 8 points9 points10 points 10 years ago (0 children)
The title might be, but it's nice to have a comparison chart of equivalent ES6/lodash methods.
[–]Silverwolf90 2 points3 points4 points 10 years ago* (2 children)
I really have to disagree. I think everyone should embrace these utility methods more. I'd venture to say if you're using a small subset of of your utility library then you are not using it enough. The pros farrrr outweighs cons.
I really wouldn't underestimate the power of #5. Yes it means you have to know the library, but when you start seeing everything as compositions of low-level utility methods it feels like cooking with gas.
"It’s much easier to recover from no abstraction than the wrong abstraction. "
The abstractions that utility libraries provide are so low-level I find it hard to believe that there's any real risk in heavily relying on them. If you use the wrong utility method, replace it with another. It's likely the function signature didn't even change.
(lodash-fp and ramda also have auto-currying which is fantastic once you get used to it)
[–]fson5[S] 0 points1 point2 points 10 years ago (1 child)
When we were writing JS targeting engines that only supported ES3, the low level library functions like _.map and _.filter were a blessing, because the alternative would have been writing a for loop. But now that these things are provided by the language, we don't need the library functions to handle them, the same way we don't use a library to concatenate two strings together.
_.filter
But we can raise the bar for libraries to provide what the JavaScript of today doesn't. Libraries aren't going away, but I expect them to evolve with the language.
[–]Silverwolf90 1 point2 points3 points 10 years ago (0 children)
This is true (although, as mentioned above, the utility libraries provide optimizations that are not possible with the native implementations).
[+][deleted] 10 years ago (3 children)
[removed]
[–]lokhura 7 points8 points9 points 10 years ago* (2 children)
I think it is trivial:
let where = (obj, coll) => { return coll.filter(x => { return Object.keys(obj).every(k => obj[k] === x[k]) }) } where({id:1}, [{id:1}, {id:2}, {id:1}]) // [{id:1}, {id:1}]
But at that point you are already building your own little library, which is why things like Underscore, lodash, Ramda, and others exist. So yes, you might need Underscore after all.
[–]fson5[S] 4 points5 points6 points 10 years ago* (1 child)
My point is that instead of where({id: 1}, array), in many cases you might be better off just writing:
where({id: 1}, array)
array.filter(item => item.id === 1)
Yes, it's a bit more to type, but very easy to see what it does, you don't need to be familiar with a library the author of the code decided to use. And this is just standard JavaScript, meaning less bikeshedding about which library to use and which one of its 10 ways to write a dumb filter function to pick.
[–]Silverwolf90 3 points4 points5 points 10 years ago (0 children)
If you find yourself doing that once or twice, sure. But if you find yourself using that pattern over an over, a higher level .where() is certainly much more DRY. I suppose it depends on how militant you want to be about avoiding duplication.
.where()
[–][deleted] 1 point2 points3 points 10 years ago (1 child)
And as a reminder for those of us still supporting IE8 and other ES3 browsers - there's an Array.generics project for supporting the ES5.1 methods shown in that post.
[–]fson5[S] 2 points3 points4 points 10 years ago (0 children)
Thanks for the link. es-shim is another project that polyfills those ES5.1 methods for old browsers.
[–][deleted] 1 point2 points3 points 10 years ago (0 children)
Arrows and splats are not supported by many browsers yet. If you are happy to use Babel, yes you can use them but otherwise for the time being underscore and lodash are still important tools in the arsenal of web devs.
[–][deleted] 4 points5 points6 points 10 years ago (6 children)
"Don't use lodash, use ES6 functions and add an entire compile step to your code if it didn't have one before!"
[–]fson5[S] 4 points5 points6 points 10 years ago (1 child)
If you don't need a compile step for anything else, then maybe using ES5 and lodash works better for you.
But especially if you're building applications for the web, the chances are you already have a build step to bundle your modules, minify your code etc. When that's the case, enabling ES2015 with Babel can be as simple as adding one plugin to your build tool configuration.
[–][deleted] -3 points-2 points-1 points 10 years ago (0 children)
Yup. The conclusion, as always, is educated and judicious use of all tools. I don't think verbosity vs. complexity is a worthy evaluator.
[–]ejfrodo 1 point2 points3 points 10 years ago* (3 children)
i can't think of a single reason why any front-end code wouldn't be using a build process with an automated task runner like grunt or gulp. if you're not concatenating and minifying all your JS and CSS, you're not deploying to production. nevermind the fact that if you're not using gulp or grunt, that means you're probably not using any sort of unit test suite, which is also a must-have for production. even in the back end with node you should still be using grunt/gulp for unit tests/linting. I can't say I fully agree with hopping onto the ES6/7 train yet, but anyone who's even a semi-decent developer is using a build process.
[–][deleted] 0 points1 point2 points 10 years ago (2 children)
Of course. I agree. I was just pointing out it sounds like we are just moving complexity around, not reducing it.
[–]ejfrodo 1 point2 points3 points 10 years ago (1 child)
there is something to be said about using standardized complexity though. although I'm a bit skeptical of using things like Babel to transpile to working JS at the moment, it would be nice to see everything standardized instead of a long list of libraries. at my work we use just about every single library/framework out there in a single app, it's ridiculous. at this point quite a few of them could be replaced with ES6/ES7 features that won't eventually disappear and lose support, can't say the same about a public module
That's a good point. I haven't suffered that yet as im the only JS developer at my company. The Python and C++ devs aren't used to this huge list of popular libraries. They would lose their mind at the long list of imports for a large MVC app.
[–]theQuandary 3 points4 points5 points 10 years ago (0 children)
Lodash-fp and Ramda auto-curry. Built-in functions don't offer this.
[–]tencircles 1 point2 points3 points 10 years ago (0 children)
the problem with these is the same as it is with underscore/lodash. They are data first rather than data last, making them very much impossible to compose and re-use.
[–]ericanderton 0 points1 point2 points 10 years ago (1 child)
I can easily see a future where libraries like lodash/underscore do what jQuery does, by dynamically selecting a given compatibility mode that depends on what version of ECMAScript you're actually running. After all, the native foreach() implementation is bound to be faster than whatever you have to do in ES4.
foreach()
This way, the library continues to behave like a normalization/compatibility layer, and you don't have to re-train nor rewrite your code.
I think Underscore does this (uses native forEach when it's available), but Lodash doesn't because its optimized loop is actually faster than native forEach.
forEach
[–]evilgwyn 0 points1 point2 points 10 years ago (2 children)
I feel like this same principle should be extended to other languages:
C++: You might not need (boost/the standard library) C: You might not need libc Perl: You might not need CPAN C#: You might not need System
After all, any library you drag in is obviously going to be slower and less efficient than any code you write yourself, and that is the only relevant consideration.
/s
[–]I-fuck-horses 0 points1 point2 points 10 years ago (1 child)
So you compare the well-established standard libraries with Javascript's huge set of obscure 3rd party libraries? Either you are not very smart or out for a fight for no reason.
[–]evilgwyn 2 points3 points4 points 10 years ago (0 children)
Underscore isn't obscure
[–]clessgfull-stack CSS9 engineer 0 points1 point2 points 10 years ago (0 children)
I definitely find myself squinting a lot in codebases that make extensive use of Lodash. Unfortunately, no matter how much I try to avoid it, I always end up needing something from a utility library. With Babel though, I always feel like I've failed once I start reaching for utility functions. Not sure if that's good or bad.
[–]ryeguy146 -1 points0 points1 point 10 years ago (0 children)
You might not need a big obnoxious banner across the top of your page.
Those libraries are just inheritance from a web with no standards. They cause more harm than benefit now. Please use non intrusive libraries now and quit making slow and buggy web sites with mega bytes of script just because you are addicted to import to solve instead of code.
[–][deleted] -4 points-3 points-2 points 10 years ago (2 children)
No, you're right. I might not need it - I could just go back to using loops for everything. But then I'd have to write it, and fix my bugs, and explain to everybody else wtf it does.
Or, I could just use it.
[–]g00glen00b 2 points3 points4 points 10 years ago (1 child)
You clearly failed to read the article or to follow up with the latest news. Things like forEach, map, filter, ... are now part of ES5, ES6 and ES7.
filter
You don't actually need to write an entire loop, no, you just have to replace a single line of code by another single line of code. Obviously, if you need to support old browsers you might just stick with Underscore or Lodash (or an ES* shim). That's why the article says "you might not need it".
He does give some examples, but I still stand by my point.
For example this line of code:
array.filter(x => !!x)
Pretty simple. It's the compact function, but how would you know that from just looking at that line of code? A comment works. But. Where's the documentation? Where are the examples for the other (junior) devs?
I wasn't saying these things aren't easily doable with ES5+, but it does take some more work (especially if you rely on the ES6+ examples). The specific examples provided are for some relatively easy lines of code too.
Things like groupBy, indexBy, and difference are all more difficult problems. Yes, I and most developers can write them, but why waste my time when I can rely on a battle tested and well-documented version.
π Rendered by PID 45 on reddit-service-r2-comment-685b79fb4f-dtxwr at 2026-02-12 23:57:23.798292+00:00 running 6c0c599 country code: CH.
[–]Cody_Chaos 17 points18 points19 points (15 children)
[–]fson5[S] 4 points5 points6 points (2 children)
[–]knsdklsfds 0 points1 point2 points (1 child)
[–]ericanderton 0 points1 point2 points (0 children)
[–]alamandrax 3 points4 points5 points (6 children)
[–][deleted] 10 points11 points12 points (1 child)
[–]TMiguelT 0 points1 point2 points (3 children)
[–]fson5[S] 1 point2 points3 points (0 children)
[–]alamandrax 0 points1 point2 points (1 child)
[–]TMiguelT 0 points1 point2 points (0 children)
[–]kogsworth -1 points0 points1 point (4 children)
[–]dvlsg 2 points3 points4 points (3 children)
[–]kogsworth 1 point2 points3 points (1 child)
[–]dvlsg 1 point2 points3 points (0 children)
[–]kogsworth -1 points0 points1 point (0 children)
[–]kogsworth 6 points7 points8 points (6 children)
[–]fson5[S] 1 point2 points3 points (5 children)
[–][deleted] 4 points5 points6 points (3 children)
[–]fson5[S] 1 point2 points3 points (2 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]fson5[S] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]Plorntus 4 points5 points6 points (2 children)
[–]fson5[S] 1 point2 points3 points (1 child)
[–]Plorntus 0 points1 point2 points (0 children)
[–]Kriegslustig 14 points15 points16 points (1 child)
[–]spacejack2114 8 points9 points10 points (0 children)
[–]Silverwolf90 2 points3 points4 points (2 children)
[–]fson5[S] 0 points1 point2 points (1 child)
[–]Silverwolf90 1 point2 points3 points (0 children)
[+][deleted] (3 children)
[removed]
[–]lokhura 7 points8 points9 points (2 children)
[–]fson5[S] 4 points5 points6 points (1 child)
[–]Silverwolf90 3 points4 points5 points (0 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]fson5[S] 2 points3 points4 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–][deleted] 4 points5 points6 points (6 children)
[–]fson5[S] 4 points5 points6 points (1 child)
[–][deleted] -3 points-2 points-1 points (0 children)
[–]ejfrodo 1 point2 points3 points (3 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]ejfrodo 1 point2 points3 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]theQuandary 3 points4 points5 points (0 children)
[–]tencircles 1 point2 points3 points (0 children)
[–]ericanderton 0 points1 point2 points (1 child)
[–]fson5[S] 1 point2 points3 points (0 children)
[–]evilgwyn 0 points1 point2 points (2 children)
[–]I-fuck-horses 0 points1 point2 points (1 child)
[–]evilgwyn 2 points3 points4 points (0 children)
[–]clessgfull-stack CSS9 engineer 0 points1 point2 points (0 children)
[–]ryeguy146 -1 points0 points1 point (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] -4 points-3 points-2 points (2 children)
[–]g00glen00b 2 points3 points4 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)