Logo

dev-resources.site

for different kinds of informations.

JavaScript Utility Libraries

Published at
12/29/2020
Categories
javascript
functional
ramda
lodash
Author
jolanglinais
Author
12 person written this
jolanglinais
open
JavaScript Utility Libraries

Comparison of JS, Ramda, and Lodash

With ECMAScript 2020 available, external libraries are not necessary for functional programming (FP) - specifically currying and composition. The two main libraries for this kind of work have been Ramda and Lodash FP. UnderscoreJS is another, but Lodash is generally thought of as an improvement on this library. Lodash is a fork of Underscore, and the history of why it forked is rather interesting.

However, it can still be a good idea to use one of these tried-and-tested libraries for more complex situations with FP. If these complex scenarios are not being taken advantage of, vanilla JavaScript can keep up with utility libraries for the most part. Some notable exceptions would be debounce from Lodash and merge from Ramda.

To reiterate, a lot of the benefits that lead to the use of Ramda and Lodash have been baked into vanilla JavaScript. Arrow functions allow for a version of currying, and along with chaining functions, can adequately compose functions. Similarly, prototypal methods are being added every version which makes Lodash less and less useful.

Note: Arrow functions don't allow for actual currying ((a, b) => {} is the same as a => b => {}, i.e. the function itself tracks how many of its arguments have been defined), just quite close.

This article will:

  • Give a brief overview of Ramda and Lodash (FP)
  • Note the cases in which it makes sense to invest in the library or not
  • Give context to a few methods which stand out
  • Provide a table summary for which library is better in which regard
  • Provide a REPL and repository for generating benchmarks

All this being public means you are free to contribute to the list and make adjustments

JavaScript

As previously stated, native JavaScript has become quite a bit more powerful over the past few years. While helper and utility libraries are still helpful, most everything in them can be reduced down to some combination of filter(), map(), and reduce().

I write more at length in my Modern Javascript Techniques article.

Use Cases:

  • Functionality needed is straightforward, with few steps or transformations needed
  • Complex functionality needing a few extra steps is not a deterrent
  • Bundle size being important
  • Learning the process that goes into these simplified helper functions from other libraries

Ramda

Ramda emphasizes a purer functional style, with immutability and side-effect free functions being at the heart of the design philosophy. Ramda is about transforming data and composing functions. This is why things like throttle and debounce are not supported because they involve side-effects. To achieve this in a pure way, functional reactive programming would be required to abstract over this with event streams.

Ramda functions are automatically curried. This allows for easily building up new functions from old ones by not supplying the final parameters. The parameters to Ramda functions are arranged to make it convenient for currying. The data to be operated on is generally supplied last. These last two points together make it very easy to build functions as sequences of simpler functions, each of which transforms the data and passes it along to the next. Ramda is designed to support this style of coding.

Ramda provides several functions that return problematic values such as undefined, Infinity, or NaN when applied to unsuitable inputs. These are known as partial functions. Partial functions necessitate the use of guards or null checks.

A remedy for this could be Sanctuary, a JavaScript functional programming library inspired by Haskell and PureScript. It's stricter than Ramda, and provides a similar suite of functions.

Use Cases:

  • Composition, taking data last and always currying
  • Specific methods, typically involving complex operations, e.g. merge, assoc, pluck...
  • Similar common methods used in multiple places
  • Complex, non-linear composition by using R.converge()

Lodash

There's little to go into here. Lodash is an extremely performant utility library. While bundle size has been an issue in the past, Lodash has become much more modularized in format. This enables build tools like webpack and parcel to do tree-shaking and removing any unused functions, which reduces bundle size.

Keep in mind that there are many functions which can be done natively.

Note: While Lodash appears faster in the benchmarks below with the _.toString() method, the results were actually not identical to the same functions in JS and Ramda.

Use Cases:

  • debounce
  • Similar common methods used in multiple places

Lodash FP

Lodash provides lodash/fp, a module to promote a more functional programming style. This module allows for curried versions of the Lodash functions. This makes Lodash a good alternative to Ramda.

Use Cases:

  • Composition, taking data last and always currying

Benchmark Results

Note that I have begun this list with common methods I and my team use, and it is in no means exhaustive. Please feel free to look into the repository and open a pull request to add further methods or tests.

Speed Readability Does Have Does Not Have
Symbols 🔵 🔶
Javascript Lodash Ramda
Downloads (week) N/A ✅ 41,323,748 7,952,372
Size (unpacked) N/A ✅ 1.41 MB 1.07 MB
Size (minified) N/A ✅ 69.9 kB 53.4 kB
Size (mini+gzip) N/A ✅ 24.4 kB 12.4 kB
Download Time N/A ✅ 488 ms 247 ms
Issues N/A ✅ 107 211
Last Publish N/A ✅ 4 month 5 month
FEATURES
Curry Yes Yes Yes
Immutable No No Yes ✅
Chainable Yes ✅ Yes Yes
Functional No Yes Yes ✅
SECURITY
Known Issues No Yes No
Dependencies No No No
COMMON METHODS
Arrays
all
concat 🔵
each 🔵
filter
find
findIndex 🔵
flatten 🔵
fromPairs
head
map 🔵 🔵
pluck
range 🔵🔶 🔶
reduce 🔵 🔵
reject 🔵 🔵
tail 🔵 🔵
uniq 🔵 🔵🔶 🔶
zip 🔵
Objects
assoc
keys 🔵 🔵
merge 🔵
omit 🔶 🔵🔶
path
pick 🔵 🔶 🔵🔶
toPairs 🔵 🔵
values 🔵
zipObj 🔶 🔵🔶
Strings
toString array 🔵
toString object 🔵
toString date
split
toLower
toUpper
Utility
clone 🔵 🔵🔶 🔶
debounce
isEmpty
isEqual 🔵
isFunction
isNil
type
Composition
Numbers 🔵
Objects 🔵 🔵
Functional 🔵
Overall 🔵 🔵
Totals 10 16 21

Test: Arrays and Collections

Name JS Time (ms) _ Time [ms] R Time [ms] Diff to JS
concat 17 19 7 +83%
each 11 15 4 +93%
filter 17 22 14 +19%
find 10 10 7 +35%
findIndex 11 15 6 +58%
flatten (deep) 1438 174 1937 +156%
fromPairs 531 512 513 +3%
fromPairs (reduce) 542 509 510 +6%
head 0 1 3 N/A
map 15 9 11 +50%
range 533 34 62 +176%
reduce 64 14 14 +128%
reject 1263 35 31 +190%
tail 1 3 6 -100%
uniq 5 4 43 +22%
zip N/A 19 7 N/A

Test: Objects

Name JS Time (ms) _ Time [ms] R Time [ms] Diff to JS
keys 145 800 109 +28%
merge (triple) N/A 100 7 N/A
omit 16 35 7 +78%
path (short) 1 3 3 -100%
path (long) 1 2 3 -66%
pick 2 12 2 -0%
toPairs 71 107 52 +30%
values 5 94 28 -139%
zipObj N/A 121 48 N/A

Test: Strings

Name JS Time (ms) _ Time [ms] R Time [ms] Diff to JS
toString (array) NOTE _ 46 151 2391 -106%
toString (object) NOTE _ 163 4 693 +190%
toString (date) NOTE _ 10 19 16 -46%
split 592 633 601 -1%
toLower 29 29 32 -0%
toUpper 25 27 30 -7%

Test: Utility

Name JS Time (ms) _ Time [ms] R Time [ms] Diff to JS
clone 0 0 15 N/A
debounce N/A 0 N/A N/A
isEmpty 1 0 0 N/A
isEqual N/A 25 106 N/A
isFunction 0 0 N/A N/A
isNil 0 0 0 N/A
type 0 N/A 0 N/A

Test: Totals

Name JS Time (ms) _ Time [ms] R Time [ms] Diff to JS
Curried / Piping Numbers 1452 3 2941 +199%
Curried / Piping Objects 825 1167 748 +9%
Curried / Piping FP N/A 25 1094 N/A
Common Methods 528 554 1155 -4%

Conclusions

Both Ramda and Lodash overlap, and should likely not be used in the same project. Depending on what data you're working on and which method you're using, these libraries can be very beneficial or unnecessary.

An approach of Vanilla-JavaScript-First should be taken, and these libraries shouldn't be used as a blanket approach to methods on data. Once you come across something that it is especially difficult to do in vanilla JavaScript, switch to one of these libraries. Which one? Comes down to taste. Both have a quite similar semantic style.

Ramda is generally a better approach for functional programming as it was designed for this and has a community established in this sense.

Lodash is generally better otherwise when needing specific functions (esp. debounce).

Either way, ensure you invest in tree shaking to minimize the bundle sizes of these libraries, because odds are you will only be using a few methods and do not need the entire library.

ramda Article's
30 articles in total
Favicon
Lenses Pattern in JavaScript
Favicon
Farewell, Ramda
Favicon
The Functional Programming jungle: Ramda versus monads and monoids
Favicon
Performance of the spread operator
Favicon
A couple of words about Ramda for React and Redux
Favicon
Ramda & Functional Programming with React & TypeScript
Favicon
Filtering an array against another array conditionally
Favicon
寫給想跳坑的 JS 新手(Part II): coding style
Favicon
寫給想跳坑的 JS 新手(Part I): map filter reduce
Favicon
A light library for pipe style programming
Favicon
Ramda is your friend
Favicon
Why use pipe?
Favicon
3 lessons I learned getting started with Ramda
Favicon
Composing functions in JavaScript
Favicon
Mutating the immutable
Favicon
Building a React app with functional programming (Part 1)
Favicon
JavaScript Utility Libraries
Favicon
Working on the "Ramda Ramp-Up Guide"
Favicon
Grandma's recipes for cooking redux
Favicon
RamdaJS: transduce
Favicon
RamdaJS: Using it for the first time
Favicon
Why you should learn Functional Programming
Favicon
Handling objects with Ramda
Favicon
How Pipeline Operator makes your code cleaner
Favicon
Better Know A Method! with Ramda's .cond(), part 1
Favicon
Easily Integrate Ramda into Your React Workflow
Favicon
A pattern to write clean Redux connected components
Favicon
Ramda library - compose, map, sum
Favicon
Functional Lenses in Javascript with Ramda
Favicon
I ❤ Ramda - Partial Application with a Special Placeholder

Featured ones: