10 Lodash Features You Can Replace with ES6

Share this article

10 Lodash Features You Can Replace with ES6
Right now, Lodash is the most depended-on npm package, but if you’re using ES6, you might not actually need it.
In this article, we’re going to look at using native collection methods with arrow functions and other new ES6 features to help us cut corners around many popular use cases.

Key Takeaways

  • Lodash is currently the most depended-on npm package, but using ES6 could eliminate the need for it in some cases.
  • ES6 features such as native collection methods, arrow functions, destructuring syntax, and rest and spread functions can replace popular Lodash functionalities like Map, Filter, Reduce, Head & Tail, and Rest and Spread.
  • ES6 can also replace Lodash features like Curry, Partial, Operators, Paths, Pick, Constant, Identity, Noop, and Chaining & Flow with the use of arrow functions, rest parameters, and the spread operator.
  • While Lodash continues to be a valuable library, the evolved version of JavaScript (ES6) provides new ways to solve problems previously handled by utility modules like Lodash.

1. Map, Filter, Reduce

These collection methods make transforming data a breeze and with near universal support. We can pair them with arrow functions to help us write terse alternatives to the implementations offered by Lodash:
_.map([1, 2, 3], function(n) { return n * 3; });
// [3, 6, 9]
_.reduce([1, 2, 3], function(total, n) { return total + n; }, 0);
// 6
_.filter([1, 2, 3], function(n) { return n <= 2; });
// [1, 2]

// becomes

[1, 2, 3].map(n => n * 3);
[1, 2, 3].reduce((total, n) => total + n);
[1, 2, 3].filter(n => n <= 2);
It doesn’t stop here, either. If we’re using a modern browser, we can also use find, some, every and reduceRight too.

2. Head & Tail

Destructuring syntax allows us to get the head and tail of a list without utility functions:
_.head([1, 2, 3]);
// 1
_.tail([1, 2, 3]);
// [2, 3]

// becomes

const [head, ...tail] = [1, 2, 3];
It’s also possible to get the initial elements and the last element in a similar way:
_.initial([1, 2, 3]);
// -> [1, 2]
_.last([1, 2, 3]);
// 3

// becomes

const [last, ...initial] = [1, 2, 3].reverse();
If you find it annoying that reverse mutates the data structure, then you can use the spread operator to clone the array before calling reverse:
const xs = [1, 2, 3];
const [last, ...initial] = [...xs].reverse();

3. Rest and Spread

The rest
and spread functions allow us to define and invoke functions that accept a variable number of arguments. ES6 introduced dedicated syntaxes for both of these operations:
var say = _.rest(function(what, names) {
  var last = _.last(names);
  var initial = _.initial(names);
  var finalSeparator = (_.size(names) > 1 ? ', & ' : '');
  return what + ' ' + initial.join(', ') +
    finalSeparator + _.last(names);
});

say('hello', 'fred', 'barney', 'pebbles');
// "hello fred, barney, & pebbles"

// becomes

const say = (what, ...names) => {
  const [last, ...initial] = names.reverse();
  const finalSeparator = (names.length > 1 ? ', &' : '');
  return `${what} ${initial.join(', ')} ${finalSeparator} ${last}`;
};

say('hello', 'fred', 'barney', 'pebbles');
// "hello fred, barney, & pebbles"

4. Curry

Without a higher-level language such as [TypeScript][5] or [Flow][6], we can’t give our functions type signatures, which makes currying quite difficult. When we receive curried functions, it’s hard to know how many arguments have already been supplied, and which we’ll need to provide next. With arrow functions, we can define curried functions explicitly, making them easier to understand for other programmers:
function add(a, b) {
  return a + b;
}
var curriedAdd = _.curry(add);
var add2 = curriedAdd(2);
add2(1);
// 3

// becomes

const add = a => b => a + b;
const add2 = add(2);
add2(1);
// 3
These explicitly curried arrow functions are particularly important for debugging:
var lodashAdd = _.curry(function(a, b) {
  return a + b;
});
var add3 = lodashAdd(3);
console.log(add3.length)
// 0
console.log(add3);
// function (a, b) {
// /* [wrapped with _.curry & _.partial] */
//   return a + b;
// }

// becomes

const es6Add = a => b => a + b;
const add3 = es6Add(3);
console.log(add3.length);
// 1
console.log(add3);
// function b => a + b
If we’re using a functional library like lodash/fp or ramda, we can also use arrows to remove the need for the auto-curry style:
_.map(_.prop('name'))(people);

// becomes

people.map(person => person.name);

5. Partial

As with currying, we can use arrow functions to make partial application easy and explicit:
var greet = function(greeting, name) {
  return greeting + ' ' + name;
};

var sayHelloTo = _.partial(greet, 'hello');
sayHelloTo('fred');
// "hello fred"

// becomes

const sayHelloTo = name => greet('hello', name);
sayHelloTo('fred');
// "hello fred"
It’s also possible to use rest parameters with the spread operator to partially apply variadic functions:
const sayHelloTo = (name, ...args) => greet('hello', name, ...args);
sayHelloTo('fred', 1, 2, 3);
// "hello fred"

6. Operators

Lodash comes with a number of functions that reimplement syntactical operators as functions, so that they can be passed to collection methods. In most cases, arrow functions make them simple and short enough that we can define them inline instead:
_.eq(3, 3);
// true
_.add(10, 1);
// 11
_.map([1, 2, 3], function(n) {
  return _.multiply(n, 10);
});
// [10, 20, 30]
_.reduce([1, 2, 3], _.add);
// 6

// becomes

3 === 3
10 + 1
[1, 2, 3].map(n => n * 10);
[1, 2, 3].reduce((total, n) => total + n);

7. Paths

Many of Lodash’s functions take paths as strings or arrays. We can use arrow functions to create more reusable paths instead:
var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };

_.at(object, ['a[0].b.c', 'a[1]']);
// [3, 4]
_.at(['a', 'b', 'c'], 0, 2);
// ['a', 'c']

// becomes

[
  obj => obj.a[0].b.c,
  obj => obj.a[1]
].map(path => path(object));

[
  arr => arr[0],
  arr => arr[2]
].map(path => path(['a', 'b', 'c']));
Because these paths are “just functions”, we can compose them too:
const getFirstPerson = people => people[0];
const getPostCode = person => person.address.postcode;
const getFirstPostCode = people => getPostCode(getFirstPerson(people));
We can even make higher-order paths that accept parameters:
const getFirstNPeople = n => people => people.slice(0, n);

const getFirst5People = getFirstNPeople(5);
const getFirst5PostCodes = people => getFirst5People(people).map(getPostCode);

8. Pick

The pick utility allows us to select the properties we want from a target object. We can achieve the same results using destructuring and shorthand object literals:
var object = { 'a': 1, 'b': '2', 'c': 3 };

return _.pick(object, ['a', 'c']);
// { a: 1, c: 3 }

// becomes

const { a, c } = { a: 1, b: 2, c: 3 };

return { a, c };

9. Constant, Identity, Noop

Lodash provides some utilities for creating simple functions with a specific behavior:
_.constant({ 'a': 1 })();
// { a: 1 }
_.identity({ user: 'fred' });
// { user: 'fred' }
_.noop();
// undefined
We can define all of these functions inline using arrows:
const constant = x => () => x;
const identity = x => x;
const noop = () => undefined;
Or we could rewrite the example above as follows:
(() => ({ a: 1 }))();
// { a: 1 }
(x => x)({ user: 'fred' });
// { user: 'fred' }
(() => undefined)();
// undefined

10. Chaining & Flow

Lodash provides some functions for helping us write chained statements. In many cases, the built-in collection methods return an array instance that can be directly chained, but in some cases where the method mutates the collection, this isn’t possible. However, we can define the same transformations as an array of arrow functions:
_([1, 2, 3])
 .tap(function(array) {
   // Mutate input array.
   array.pop();
 })
 .reverse()
 .value();
// [2, 1]

// becomes

const pipeline = [
  array => { array.pop(); return array; },
  array => array.reverse()
];

pipeline.reduce((xs, f) => f(xs), [1, 2, 3]);
This way, we don’t even have to think about the difference between tap and thru. Wrapping this reduction in a utility function makes a great general purpose tool:
const pipe = functions => data => {
  return functions.reduce(
    (value, func) => func(value),
    data
  );
};

const pipeline = pipe([
  x => x * 2,
  x => x / 3,
  x => x > 5,
  b => !b
]);

pipeline(5);
// true
pipeline(20);
// false

Conclusion

Lodash is still a great library, and this article only offers a fresh perspective on how the evolved version of JavaScript is allowing us to solve some problems in situations where we would have previously relied on utility modules. Don’t disregard it. Instead, next time you reach for an abstraction, think about whether a simple function would do instead! This article was peer reviewed by Mark Brown. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

Frequently Asked Questions (FAQs) about Lodash and ES6

What are the key differences between Lodash and ES6?

Lodash and ES6 are both JavaScript utilities that provide helpful methods for programming. However, they differ in several ways. Lodash is a library that provides utility functions for common programming tasks using the functional programming paradigm. It includes methods for array manipulation, object and number manipulation, etc. On the other hand, ES6, also known as ECMAScript 2015, is a version of JavaScript that includes new features and enhancements for complex applications, including classes, modules, arrow functions, promises, and more. While Lodash provides a consistent cross-environment, ES6’s support depends on the JavaScript engine implementation.

Is Lodash still relevant with the advent of ES6?

Yes, Lodash remains relevant even with the advent of ES6. While ES6 has introduced several new features that overlap with Lodash’s functionality, Lodash still offers several benefits. It provides a rich set of utility functions that are optimized for performance and can handle edge cases well. It also offers consistent cross-browser support, which is particularly useful for applications that need to support older browsers.

Can I replace Lodash with ES6 completely?

While ES6 does provide several features that overlap with Lodash, it may not be possible to replace Lodash completely with ES6. Lodash provides a number of utility functions that are not available in ES6. Moreover, Lodash functions are generally more performance-optimized and can handle edge cases better than their ES6 counterparts. Therefore, whether you can replace Lodash with ES6 or not depends on your specific use case.

How can I transition from using Lodash to ES6?

Transitioning from Lodash to ES6 involves identifying the Lodash functions you are using and replacing them with their ES6 equivalents, if available. You can use tools like ‘You Don’t Need Lodash/Underscore’ to help identify the ES6 equivalents of Lodash functions. However, keep in mind that not all Lodash functions have ES6 equivalents, and you may need to write custom code to replace some functions.

What are some examples of Lodash functions and their ES6 equivalents?

Here are a few examples of Lodash functions and their ES6 equivalents:

    1. _.each vs Array.prototype.forEach

    1. _.map vs Array.prototype.map

    1. _.filter vs Array.prototype.filter

    1. _.reduce vs Array.prototype.reduce

    1. _.find vs Array.prototype.find

Are there performance differences between Lodash and ES6?

Yes, there can be performance differences between Lodash and ES6. Lodash functions are generally more performance-optimized than their ES6 counterparts. However, the performance difference is usually negligible for most applications and should not be the primary factor in deciding whether to use Lodash or ES6.

What are the benefits of using Lodash over ES6?

Lodash offers several benefits over ES6, including a rich set of utility functions, better performance optimization, better handling of edge cases, and consistent cross-browser support. It also provides a functional programming paradigm, which can make your code more readable and easier to test.

What are the benefits of using ES6 over Lodash?

ES6 offers several benefits over Lodash, including new features like classes, modules, arrow functions, promises, and more. It also provides a more modern and standardized approach to JavaScript programming. Moreover, since ES6 is a part of JavaScript, using ES6 features does not require adding an additional library to your project, which can reduce the size of your JavaScript bundle.

Can I use Lodash and ES6 together?

Yes, you can use Lodash and ES6 together. In fact, many developers use both in their projects. You can use ES6 features where they are available and fall back to Lodash for utility functions that are not available in ES6 or for better cross-browser support.

How can I decide whether to use Lodash or ES6 in my project?

The decision to use Lodash or ES6 in your project depends on several factors, including your project requirements, the browsers you need to support, your familiarity with Lodash and ES6, and more. You can use tools like ‘You Don’t Need Lodash/Underscore’ to help identify the ES6 equivalents of Lodash functions and decide whether to replace them. However, keep in mind that not all Lodash functions have ES6 equivalents, and you may need to write custom code to replace some functions.

Dan PrinceDan Prince
View Author

Digital Nomad and co-founder of UK based startup Astral Dynamics.

arrow functionscurryingES2015es6functional-jsjameshlearn-modernjslodashmodernjsmodernjs-hubpartial application
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week