Pure JavaScript Functions as a Replacement for Lodash
A brief overview of pure replacement functions over Lodash/Underscore.js
This post is a compilation of recipes of the most commonly used Lodash/Underscore.js utility functions to help you understand how much can be done using pure Javascript functions. Some of these functions are supported by ES5 and some require ES6 support.
The core design aspect of libraries like Lodash or Underscore.js is functional programming
where you have pure functions that have no side-effects or do not mutate state. Well, the formal definition follows below…
What is functional programming anyway?
There are many ways to explain functional programming as a concept, but the definition below is succinct:
Functional programming is a style of programming which models computations as the evaluation of expressions. Contrast this with imperative programming where programs are composed of statements which change global state when executed. Functional programming typically avoids using mutable state and favors side-effect free functions and immutable data instead.
The key point to note is that the functions you write must not have any side-effects. That way it’s easier to test, maintain and most of all predictable.
Let us start with simple examples to illustrate the point and work our way to complex functions to see where the curve flips between native functions and library functions.
Tip: Install only the functions you need as Bit components
Using Bit you can strip any function, component or module from any of your libraries and make it individually reusable- with 0 refactoring. Try it out.
Example — lodash as a collection of reusable functions to use and share
1. find
The first function we will illustrate is the one that we use often. Let’s try to find the first element in a collection that satisfies a condition
So, this is a very simple example and let’s investigate the performance of both these functions:
You can inspect the benchmark code and play with variations using the playground below:
This is not to conclude that native functions are always performant over their Lodash counterparts. There are some functions that are complicated enough that it is possible that we write an implementation that is under-performant than what the library offers. But, when there is a choice of the native function being simple and more readable, you should definitely consider it as a better alternative.
2. filter
array.filter
helps you extract all elements from a collection that satisfy a specific condition
3. first and rest
There will many use-cases to get the first element in a collection and dump the rest to another.
You would have probably used the spread operator ...
in other contexts. Here, we are using it to de-structure array elements.
The performance benefits of first
and rest
are left as an exercise to the reader.
4. each
You are better off using a vanilla for
loop than using any of the built-in iterators. This is one such use-cases where using lodash functions pay off.
The benchmark results look interesting:
Lodash’s each
function is much faster because of the implementation decisions taken by the library that are browser specific.
The lo-dash developers explain that the relative speed of the native
forEach
varies among browsers. Just becauseforEach
is native does not mean that it is faster than a simple loop built withfor
orwhile
. For one thing, theforEach
has to deal with more special cases. Secondly,forEach
uses callbacks, with the (potential) overhead of function invocation etc.
5. every
This function tests whether all elements in the array satisfied a specific condition. And the native version of it much faster!
6. some
This function tests whether at least one of the elements in the array satisfied a specific condition
7. includes
Check whether an element is contained or included in a collection.
8. uniq
Find unique elements in an array
We will be leverage the javascript’s Set
data structure to convert an array to a set and convert it back to an array using the spread operator. Now, let’s see if it helping with performance to go through two conversions.
Now, there is a better way to filter the elements using the following snippet
elements.filter((v, i, a) => a.indexOf(v) === i)// definition: filter(callback(value, index, array)
Whether to use native functions or the lodash version is for you to decide…
9. compact
This is a useful function to remove falsey or undefined values from an array.
Now, we used a bit of syntactic sugar there to convert every element to boolean using array.filter(Boolean)
to only return non-falsey values back.
So, having looked at multiple examples, the factors to take into consideration when choosing native functions over external libraries:
- can you afford to include an external library in your application. With techniques like tree-shaking, you might be only including the modules that are used, but still would you want to use an external function?
- in some cases, would you be willing to sacrifice code readability for performance or what is paramount to you?
Hope this post helps to serve as a starting point to take a decision in the right direction… thanks for reading :)!