Luke M

Lodash notes

2025-02-24

Comparison to JavaScript ES6

For most of my career, I've stuck with Javascript ES6 Array.prototype patterns for manipulating collections. These are for the most part, good enough.

However, there are some benefits to using Lodash; it performs much better with very high amounts of records, and its syntax can be more idiomatic.

Turn a record into an array

I prefer to use Lodash with the _.chain function so that the syntax is similar to JS ES6 collection methods that I'm used to.

// ES6
Object.values(data);

// Lodash
_.chain(data).values().value();

Implicit vs explicit chaining

A newer syntax allows the chain function to be implied, and the .value() to be dropped from the end.

Explicit chaining with _.chain(...)

_.chain([]).uniq().sum().value();

Implicit chaining with _(data)

  • Implicit chaining creates a Lodash wrapper object which must be unwrapped
  • A chain-breaking method like sum(), max(), or find() unwraps the value automatically, therefore .value() can be omitted.
  • A chainable method like uniq(), map(), filter() returns a wrapped value, and .value() is required to extract it.
_(data).uniq().sum(); // Does not return a collection therefore omit .value()
_(data).uniq().value(); // Returns a collection, therefore requires .value()

While both chaining styles use identical lazy logic, and the difference is purely syntactic, it is recommended to use _(data) (implicit chaining) because it has cleaner syntax and is more idiomatic.

Lazy-evaluation

By default, Lodash will attempt to use lazy evaluation.

Lazy evaluation uses these techniques to reduce the amount of iterations in an enumeration:

  • Pipelining: Applies all operations per element in a single pass.
  • Short-circuiting: Some methods like take() stop iteration early.

This results in much better performance on large collections.

There are certain functions that are incompatible with lazy-evaluation- if you use them, the lazy evaluation will be stopped, and eager evaluation used instead. Examples include sortBy(), reverse(), each(), forEach(), head(), and last().

Debugging Lodash

The Lodash tap method calls a function on the collection, without affecting it. It is extremely useful for debugging, because you can move the _.tap(console.log) to any point in your Lodash chain to inspect it.

// ES6
data.forEach((x) => {
  console.log(x);
  return x;
});

// Lodash
_.chain(data).tap(console.log).value();

Sorting

One reason to use Lodash is that ES6's sort() mutates the original array, while Lodash's sortBy and orderBy return a new sorted array.

Sorting by date

The use of JavaScript's Date object is the fastest way to blood on the floor.

There are several problems with it; such as performance when working with large datasets, no timezone, and the fact that Dates are mutable (so any arithmetic performed on them permanently changes them).

For this reason, when sorting dates, I'm always sorting a string. Because sort works on alphanumeric values, sorting by date is usually as easy as sorting the strings.

Sort by date

// ES6
date.sort((a, b) => b.date.localeCompare(a.date));
// Lodash
_.chain(data).orderBy("date").value();

Sort by optional date

// ES6
data.sort((a, b) => {
  const dateA = a.date || "";
  const dateB = b.date || "";
  return dateB.localeCompare(dateA);
});
// Lodash
_.chain(data)
  .sortBy((x) => x.date || "")
  .reverse()
  .value();

Filtering

Filter out null values

The _.compact() function can be used to remove nullish values from the collection.

_(data).compact();

Filter out expired dates

// Lodash
_.chain(data).filter((x) => !x.date || x.date > new Date().toISOString());