Lodash v3.0.0
lodash.comWe switched from underscore to lodash several months ago, and haven't regretted it. The fact that lodash follows semver is huge. Underscore has introduced serious breaking changes in minor point-releases more than once, which is completely unacceptable for a utility library.
Semver isn't a requirement nor be-all-end-all, though.
It is, however, amazingly convenient and capable of saving a lot of time in bug fixes.
Isn't what's a "requirement" something that THEY get to decide for their code base?
The lodash & lodash-compat npm packages now come with modules baked in too.
Perfect for Browserify!
// load the modern build
var _ = require('lodash');
// or a method category
var array = require('lodash/array');
// or a method
var chunk = require('lodash/array/chunk');
This is great. It combines trust and quality with modularity.Really nice to see that there's now an auto-curried, function-first version, lodash-fp! I've been really attracted by Ramda JS recently for this reason.
I've been looking for some real-world examples of how currying might be useful in javascript. Haven't not used a language which supports currying for any real world project, I'm interested to know how it can help.
I found a page [1] which talks about currying in javascript, then says "Are there practical uses for currying in JavaScript? Not really."
Can you point me at anything which will help me see why it's useful?
[1] http://benalman.com/news/2012/09/partial-application-in-java...
Some code that I've written using Ramda.js:
With this code I can merge any two lists (list1 and list2) on any two properties (Property1 and Property2), and then group the result. I use this to synchronize client and server data.var predicateListFunc = function(props) { return R.allPredicates(R.map(R.curry(R.eqProps), props)); } var compareProperties = R.unapply(predicateListFunc); var mergeLists = R.unionWith(compareProperties("Property1", "Property2")); var groupById = R.groupBy(R.prop("Property1")); var getGroups = R.compose(R.toPairs, groupById, mergeLists); var groups = getGroups(list1, list2);I don't know if this answers your question, since I wrote in about an hour of learning Ramda.js, and there might be an easier way of doing it.
Here's a fiddle:
This slideshow [1] by one of the authors of Ramda.js goes over a JavaScript example in OO style and refactors it to functional style. Currying is used to complete the refactoring.
I've linked to the slides on currying but you'll need to back up to follow the whole example.
[1] http://scott.sauyet.com/Javascript/Talk/FunctionalProgrammin...
Wow, thanks, that presentation is pure gold! The best thing about FP (and moving into it from the OOP world) I've ever seen: clear, easy to follow, based on a practical example and really presenting the sense behind the use of FP.
There is an excellent talk called "Underscore, you're doing it wrong!". The talk explains how well designed param order with currying leads to very short and expressive code -- and how underscore missed the boat. This aspect of it should be interesting as it's related to this post. It's well worth the watch.
I was just about to post exactly this. Well worth a watch. It was this talk which finally made currying "click" for me. And serendipitously the topic is the improvements currying and swapping args can make to the underscore (or lodash!) API.
I even tweeted to @jdalton on announcement "hey lodash, you're doing it right" :)
One situation where I felt compelled to use lots of currying was when I was working with a promise library for async code. There are lots of little callbacks you need to use and you benefit from having combinators that act as function versions of js operators, like "+", "[]" and so on and currying helps cut down on the number of combinators you need.
That said, I didn't end up being a big fan of it in the end. Other people can get confused by the new abstractions the combinators introduce and whenever you pass the wrong number of arguments to a function you end up with very tricky runtime errors (this isn't an issue in Haskell because the type system checks this for you)
That sounds like an interesting approach.
Would mind posting an example?
(I was wondering what something like Flow.js would make of the code. i.e. Could it make catching those errors easier)
Cheers.
Its been a while since I worked with this so this is kind of a shitty example out of the top of my head:
If you have code that looks like this:
You can write it more succinctly using a combinator library instead of writing the callback out by hand:var user_list = fetch_json() .then(function(data){ return data.users })
Similar things also apply on other code that uses callbacks like maps, filters, etc. I also had combinators for other common JS operators (set, "+", "==", ...)var user_list = fetch_json() .then(get('users'))The point where currying comes in is that it lets you define a single "get" function instead of a separate versions for one and two arguments:
That said, there are some downsides to using combinators instead of writing the callbacks by hand. If you need to debug something the stack traces are harder to follow and currying doesn't play nice with functions like Array.prototype.forEach that pass "extra" parameters to the callbacks.//curried x = get('users', data) y = get('users')(data) //non curried x = get2('users', data) y = get1('users')(data)In the end the feeling I got was that trying to make JS more functional is not worth the trouble. If I could go back I would try to replace the promises with something less intrusive in terms of coding style, such as generators/coroutines.
Ah, I see.
Yes, I think I've come to the exactly same conclusions in the past, both with regard to promises and curried (or partially applied functions for that matter).
This may only apply to me but I've found that without strong, static typing to help out, my brain starts to melt sometimes trying to workout what heavily curried JS functions actual do without using a debugger.
"A programmer’s pipe-dream is to write code, and be able to use it repeatedly with little effort. It’s expressive because you write in a way that expresses what is needed, and it’s reuse because.. well, you’re reusing. What more could you want? Curry can help.":
It makes the syntax a bit better for combining functions. Seems like a small thing, but with all the complaining about nested callbacks I guess it's good. See Ramda, who came up with this concept, for a deeper discussion of the benefits.
Coming from a Python background, Ramda's (function, iterable) feels way more natural than vice-versa:
See release notes and changelog: - https://github.com/lodash/lodash/releases/tag/3.0.0 - https://github.com/lodash/lodash/wiki/Changelog
I dig laziness, but why is `forEach` lazy? That's the only one that invokes immediately in libraries like Lazy.js.
It's only lazy if it's part of a chain
Chaining is deferred until `value()` is implicitly or explicitly called. However shortcut fusion does not apply to `forEach`.
Thanks for the link, I was expecting a CHANGELOG file in the project.
Q: "What does it do?"
A: "A utility library delivering consistency, modularity, performance, & extras."
Q: "Yeah, but what does it do?"
A: "Oh, nothing but it does it consistently, modularly and performant. We also have functions for string handling in the extras module."
It's extra stuff that should be in the standard library but isn't.
These days, a lot of it is actually in the standard library - for example, array maps - and invoking lodash just calls the es5/es6 built in, with a slightly uglier syntax.
But if you want backward compatibility, you still probably want to use something like Lodash. I'd also argue that Lodash's/Underscore's interface is far better thought out than the standard library. The standard library has so many absurd gotchas, like `["2", "2", "2", "2"].map(parseInt)`. The verbosity of Javascripts lambdas also makes composition of simple parts more arcane looking than necessary, and having a whole bunch of composable/chainable utility functions does a lot to help people write self-documenting code.
> But if you want backward compatibility, you still probably want to use something like Lodash.
A few years ago, sure, but these days I'd use es6-shim. The code will be shorter, have more documentation around the internet, and when old browsers die you won't have to change anything to be on standard JS.
lodash offers features and performance over es5/6 built-ins.
Interestingly, in practice lo-dash actually doesn't proxy through to the native implementation for things like map and forEach. Just using loops ends up being more performant because of some edge cases in the ES5 spec for those methods that lo-dash and underscore don't follow.
The most important feature is chaining and lazy evaluation.
I think the most useful functions are the typechecking utilities (typeof in javascript is the most useless keyword the human kind engineered in a language).
In the end is a very nice library to work with when it does not get in the way (of course, if you are using `_.each([], fn)`, you should think again and use `Array#forEach` or a nice `for`)
>of course, if you are using `_.each([], fn)`, you should think again and use `Array#forEach` or a nice `for`
You probably shouldn't if you're in a hot path. LoDash actually outperforms some native ES5 features, Array#forEach being one of them IIRC.
It should start being called "the jQuery effect" since it's one of those libraries that comes to be considered by the community as a standard way to patch the environment. Not only that, but some people begin to develop very strong, quirky aesthetic preferences for seeing it in their code.
I also had no idea what this was until I got to the bottom of the page. Looks like a "better underscore.js". They should just say something to that effect upfront.
They used too say that when the project was new. Perhaps now they feel the project is established enough that it can stand on it's own without trying to position it as a drop-in replacement for underscore.
I followed the link and saw "lodash" for the first time today. Oh, it's a library! With an API! In various formats!
I always appreciate it when the top of the project page provides a one-liner explaining just what it is I'm looking at.
I wish that it had mentioned what it was a library for. Took me longer than it should have to identify that it was a Javascript library.
I probably should have guessed, but I hate guessing wrong and missing out on something I could really use.
Yeah,the doc sucks a bit because you're supposed to know it's a "fork" of underscore. They could do a better job at explaining why lodash is useful, because it definetly is.It can really reduce the amount of js code one is writing by 2 or 3.
In a nutshell it's a collection of functions that work on arrays,objects and functions.It's a toolbox.
Yep, one might think that one could manage a decent description by version 3.0.0
lol, added "JavaScript" to the description :)
Lodash is an incredible accomplishment, and having it vastly improves the Javascript authorship process over the standard library.
That being said, I still can't believe we don't have a flatMap:
https://github.com/lodash/lodash/issues/812 https://github.com/jashkenas/underscore/issues/452 (Underscore repo, but still Mr. Dalton, author of Lodash, opposing.)
He explained how to add a flatMap in 2 lines in the first linked issue. It sounds pretty trivial to add per app.
It is alternative to underscore.js? Or extensions for underscore.js? Not clear from the page...
It's supposed to be better, faster, and stronger (more functions) than underscore.
It's also under active maintenance from an enthusiastic dev. Do your own research, but I go with lodash.
Lazy.js claims to be even faster than both with support for lazy evaluation to boot. Not quite a drop-in replacement like lodash is, but I think it only requires a minor tweak.
seems like lodash now has lazy evaluation as well when using the _(obj).method() syntax:
http://filimanjaro.com/blog/2014/introducing-lazy-evaluation...
A new feature in 3.0 is that lodash now supports lazy evaluation using the chaining API from 2.x.
So 2.0 code which used chaining is now broken if it doesn't explicitly exhaust the chain?
Lazy.js is however not that active. I guess the community around it still needs to develop.
I've been playing around with getting Mori[0] more js-like, from more idiomatic function names and argument order (fn as the last argument, released) to playing around with a chaining API. Ideally we should be able to wrap javascript values, manipulate via idiomatic chaining (similar to Lodash), while getting most of the benefits from highly-tuned persistent data structures, lazy sequences, etc.
e.g.
expect(_([1,1,1,1,2,2,3,4,5,6,6]).distinct().conj(7).out()).toEqual([1,2,3,4,5,6,7]);
Here's a small set of specs showing early ideas https://github.com/swannodette/mori/blob/8e82b15b35b2989d4a2...I've tended to avoid both underscore and lodash because they're both in the slew of monolithic pre-npm libraries, however the lazy evaluation looks interesting. I wouldn't be surprised to find a library that handles lazy eval without all the extra features Lodash brings.
For the shops who don't live and breath js and whose js work is almost entirely browser-based, these monoliths are great. I, for one, am bummed that the js market is moving away from monoliths. e.g. YUI shutting down.
That's an interesting perspective. I don't have any inherent problems with large libraries, but my problem with some of these 'monoliths' is that other libraries start to depend on the entire library when they only need a small piece of functionality that the library provides.
Substack wrote an article [1] explaining some of the problems that monolithic libraries cause in an ecosystem.
thanks, I'll check that out.
With browserify (or webpack) you can require just the functions you want, and only those (and their dependencies) end up in your code base. This is covered in the changelog
There is lazy.js (http://danieltao.com/lazy.js/). Also, lodash is highly factored into pieces if you don't want the whole thing.
lodash offers modules for node, es6, amd, individual npm packages and bundled in the primary npm package so you can even do require('lodash/array/chunk').
I remember trying this a while ago and being disappointed at the amount of dependency code brought in for a rather trivial function, but the modularization is looking much better than it was last time I took a look.
Whoah: "Tested in Chrome 39-40, Firefox 34-35, IE 6-11, Opera 25-26, Safari 5-8"...
IE6+ support! I wonder if that's real, full support, or more like a "there are serious bugs we'll probably never fix for old IE".
Working with old IE versions is loathsome (but still required for some of us), so libraries that just work there are much appreciated.
Yap it's tested in IE6 & full support. https://saucelabs.com/u/lodash
For anyone interested in learning more about lodash, Adam Boduch's "Lodash Essentials" book just got released, and covers everything in v3 (he delayed it to make sure it covered v3).
The changelog at https://github.com/lodash/lodash/wiki/Changelog gives some nice examples of breaking changes for anyone moving from v2.x
So going modern means breaking in PhantomJS, that is a bummer.
It doesn't mean it's breaking in PhantomJS. The modern build lacks some iteration fixes for older environments is all. In the case of PhantomJS it's edge iteration of things like `arguments` objects. The modern build won't error out even in IE6.
It's not clear to me: Is that list at the bottom new things in v.3?
Is there build of this that lets me require a single function?
Every function is published to npm as a module: https://www.npmjs.com/browse/keyword/lodash-modularized
Is this the same as underscore.js?
Thanks - it sounds as if you could use it as a drop in replacement for underscore.
Yes, you can. I've successfully done so in a Backbone/React app.
The _.chain() method furthermore gives a nice functional style ways of building lists which is useful when building UI in React, like so:
var list = _.chain([1, 2, 3, 4, 5]) .filter(function (value) { return value > 2; }) .map(function (value) { return value; }); console.log(list); // prints: // [3, 4, 5]That's not "furthermore". chain/value also exists in underscore.
Also your code was broken in Lodash 2 (it'd return a lodash object, not a list) and is more broken in Lodash 3 (chains are now lazy), so your code does just about nothing until you force the iterator's evaluation)
lodash v2 offers an Underscore build that aligns its chaining and other API with Underscore providing a full drop-in replacement. However because lodash is a superset of Underscore those using the Underscore build lose out on additional methods, optimizations, & cross environment fixes.
Over the last year Underscore has align more & more with lodash’s API so the need for a separate Underscore build has diminished. If you still need compatibility around some of the edges you should leverage modules in lodash v3 to supplement your Underscore use until the time you can drop Underscore completely.
Already submitted: https://hn.algolia.com/?query=lodash&sort=byPopularity&prefi...
Seems like no one cares. Strange.
It's easy to not care when there's no context or indication as to what Lodash might be. Too many links, not enough time.
I did click -- but only because a previous comment made it seem like Lodash was something related to functional programming. If it hadn't been for that comment, I have ignored the post, because I wouldn't have had a clue WTH Lodash was.
Now, sure, people who've already used or heard of Lodash are going to know, but they're probably already following it on Github. :-) The unwashed masses like me won't have any idea.
I guess the key here is to try to make the title give some indication of what the thing is.
There are two kinds of JS developers, those that use LoDash at least once per function and those that have never heard of it!
I use Lodash but i see not point in this announcement in its current form - what changed exactly?
[edit] Changelog is there https://github.com/lodash/lodash/wiki/Changelog
Some decisions sound really weird, such as the fact that forEach is now lazy. It is not a standard replacement anymore, and probably break the compatibility for quite a few apps (even if I'm deeply convinced that we should all use the native functions and shim them when needed).
It's only lazy when using the chaining syntax - and that one was never a standard replacement since `_.map(arr, fn)` returns a wrapper around a value and not a value.
Are you talking about this?
Seems that the only apps this change will break are those who are using side effects in a chain. Which is a pretty dubious choice, IMO. Especially given that Lodash is a "functional programming library".// in 2.4.1 _([1, 2, 3]).forEach(function(n) { console.log(n); }); // => logs each value from left to right and returns the lodash wrapper // in 3.0.0 _([1, 2, 3]).forEach(function(n) { console.log(n); }); // => returns the lodash wrapper without logging until `value` is called _([1, 2, 3]).forEach(function(n) { console.log(n); }).value(); // => logs each value from left to right and returns the array