Common Javascript Functions Replacing Lodash

In today’s world of JavaScript, there are a lot of tools that fix the same problem with slightly differing methods. Some of the tools are driven by simplicity, a few by configurability, and others by extensibility. Lodash is one of those handful of libraries that have been created to solve a growing problem that, fortuitously, because of Microsoft’s foresight, no longer exists.

Lodash vs Pure JavaScipt Functions; Source: JavaScript in plain English

Lodash is functional-style programming and a chain of JavaScript utility functions used to make the lives of front-end developers a whole lot less complicated. It is an insanely famous library that still receives 26 million downloads per week. There is a lot of network support for the library, and there are 115,000 libraries that depend on it as well.

The core design aspect of libraries like Lodash or Underscore.Js is functional programming, where you have pure functions that don't have any side effects or do not mutate.

What is functional programming?

There are many ways to explain functional programming as a concept, but the definition below is clear:

Functional programming is a style of programming that models computations through the assessment of expressions. Contrast this with imperative programming, in which applications are composed of statements that change the global state when executed. Functional programming generally avoids the use of mutable states and favors side-effect-free functions and immutable data instead.

The key point to notice is that the functions you describe should not have any side effects. That way, it’s simpler to test, maintain, and most of all, is predictable. Let us start with easy examples to replace Lodash functions with vanilla Javascript functions.

JavaScript instead of Lodash; Source: Geekflare

Here are some Lodash functions that can be replaced with Javascript functions:

_.map(), _.reduce(), and _.forEach()

_.map(), _.reduce(), and _.forEach are regularly used functions while processing collections, and ES6 presents direct support for them:

_.reduce()

Lodash:

const numbers = [1, 2, 3, 4];
const sum = _.reduce(numbers, (acc, num) => acc + num, 0);

JavaScript:

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, num) => acc + num, 0);

Expected Output:

10

But Lodash’s _.map() is more powerful in that it works on objects, has iterate and predicate shorthands, lazy evaluation, guards against null parameters, and has better performance.

_.map()

Lodash:

const numbers = [1, 2, 3, 4];
const mappedNumbers = _.map(numbers, (num) => num * 2);

JavaScript:

const numbers = [1, 2, 3, 4];
const mappedNumbers = numbers.map((num) => num * 2);

Expected Output:

[2, 4, 6, 8]

Iterate over objects. To iterate over an object in ES6, there are numerous ways.

With Lodash, there’s a unified _.forEach for each array and object.

 _.forEach 

Lodash:

const numbers = [1, 2, 3, 4];
_.forEach(numbers, (num) => console.log(num));

JavaScript:

const numbers = [1, 2, 3, 4];
numbers.forEach((num) => console.log(num));

Expected Output:

1
2
3
4

Although ES6 provides forEach for the newly added Map types, it takes some effort to first convert an object into a Map.

_.merge()

Lodash:

const obj1 = { name: "John" };
const obj2 = { age: 25 };
const mergedObject = _.merge({}, obj1, obj2);

JavaScript:

const obj1 = { name: "John" };
const obj2 = { age: 25 };
const mergedObject = { ...obj1, ...obj2 };

Expected Output:

{ name: "John", age: 25 }

_.concat()

The concat function in Lodash will create a new array that concatenates the array with any additional arrays and/or values. It will not change the original array. It's easy and simple to use. The same goes for the Javascript native concat method. But one is the use of libraries (Lodash), and the other is Javascript unique concatenation. The syntax is also different. But the native  Javascript concat wins. 

Lodash:

const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const newArray = _.concat(array1, array2);

JavaScript:

const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const newArray = array1 + array2;

Expected Output:

"1,2,34,5,6"

_.sort()

Lodash:

const numbers = [3, 1, 4, 1, 5, 9, 2];
const sortedNumbers = _.sort(numbers);

JavaScript:

const numbers = [3, 1, 4, 1, 5, 9, 2];
const sortedNumbers = [...numbers].sort((a, b) => a - b);

Expected Output:

[1, 1, 2, 3, 4, 5, 9]

_.isArray(), _.isObject(), _.isUndefined()

Lodash:

const value = [1, 2, 3];
const isArray = _.isArray(value);
const isObject = _.isObject(value);
const isUndefined = _.isUndefined(value);

JavaScript:

const value = [1, 2, 3];
const isArray = Array.isArray(value);
const isObject = typeof value === 'object' && value !== null;
const isUndefined = value === undefined;

Expected Output:

isArray: true
isObject: true
isUndefined: false

Math functions like _.min(), _.max(), and _.add()

Lodash:

const numbers = [2, 7, 1, 8, 4];
const minValue = _.min(numbers);
const maxValue = _.max(numbers);
const sum = _.add(3, 5);

JavaScript:

const numbers = [2, 7, 1, 8, 4];
const minValue = Math.min(...numbers);
const maxValue = Math.max(...numbers);
const sum = 3 + 5;

Expected Output::

minValue: 1
maxValue: 8
sum: 8

_.assignIn()

We use this function to add a brand-new property to an object. Additionally, we can also assign the property of one object to another object. JavaScript additionally has provisions for these types of requirements. We can gain this with the following methods:

Lodash:   

const first_object = { age: 30 };
const second_object = { city: "London" };
const mergedObject = _.assignIn({}, first_object, second_object);   

JavaScript:   

const first_object = { age: 30 };
const second_object = { city: "London" };
const mergedObject = { ...first_object, ...second_object };

Expected Output:   

{ age: 30, city: "London" }

_.values()

This function is available to get the values of each property within the object collection. We can use JavaScript because it has a similar function with an equal name to do this task.

Lodash:   

const users = {
Eva: { emp_id: 201, location: "Germany" },
Frank: { emp_id: 202, location: "Spain" },
Grace: { emp_id: 203, location: "Italy" },
Henry: { emp_id: 204, location: "France" }
};
const values = _.values(users);

JavaScript:   

const users = {
Eva: { emp_id: 201, location: "Germany" },
Frank: { emp_id: 202, location: "Spain" },
Grace: { emp_id: 203, location: "Italy" },
Henry: { emp_id: 204, location: "France" }
   };
const values = Object.values(users);  

Expected Output: 

[
{ emp_id: 201, location: "Germany" },
{ emp_id: 202, location: "Spain" },
{ emp_id: 203, location: "Italy" },
{ emp_id: 204, location: "France" }
]   

_.pick()

As the name indicates, the pick function is used to collect property from an object. We can pick out more than one property from the object, and it'll return the response within the object.

Let us use the sample records from the ‘Users’ instance in point 2:

Lodash:   

const pickedData = _.pick(users, ["Eva", "Grace"]);

JavaScript:   

const pickedData = {
Eva: { emp_id: 201, location: "Germany" },
Grace: { emp_id: 203, location: "Italy" }
};   

Expected Output:

You can use the object destructuring syntax to implement this

let data = {
Eva: { emp_id: 108, location: "UK" },
Grace: { emp_id: 197, location: "Italy" },
Frank: { emp_id: 203, location: "France" }
Henry: { emp_id: 204, location: "France" }
};

const picked = (({ Eva, Grace }) => ({ Eva, Grace }))(data);
// picked will have the picked keys
{
Eva: { emp_id: 201, location: "Germany" },
Grace: { emp_id: 197, location: "Italy" },
}   

_.omit()

Omit is used to remove the chosen property from the input and give the new object in the response. We can use simple JavaScript code to get this result too.

We will use the above user example:

Lodash:   

const omittedData = _.omit(users, ["Eva", "Frank"]);

JavaScript:   

You can again use the spread operator to omit some keys

let data = {
Eva: { emp_id: 108, location: "UK" },
Grace: { emp_id: 197, location: "Italy" },
Frank: { emp_id: 203, location: "France" }
Henry: { emp_id: 204, location: "France" }
};

let {Eva, Frank, ...omittedData} = data;

// omittedData will have the remaining keys
{
Grace: { emp_id: 203, location: "Italy" },
Henry: { emp_id: 204, location: "France" }
};

Expected Output:   

{
Grace: { emp_id: 203, location: "Italy" },
Henry: { emp_id: 204, location: "France" }
}

_.compact(): Array

Compact is an excellent function to sanitize an array. This function is used to dispose of all unrecognized values in the array. We can handle values like null, false, undefined, Nan, 0, and the use of compact. In JavaScript, we can use the filter method to dispose of the unrecognized values from an array.

Lodash:   

const arr = [22, 'world', undefined, 3, 15.7, null, 'hello'];
const compactedArray = _.compact(arr);  

JavaScript:   

const arr = [22, 'world', undefined, 3, 15.7, null, 'hello'];
const compactedArray = arr.filter(value => !!value); 

Expected Output:   

[22, 'world', 3, 15.7, 'hello']

_.uniq():Array

The uniq function is also an array-based utility. This function is superb for getting rid of repeated values from an array.

Lodash:   

const arr = [1, 2, 3, 'apple', 'orange', 4, -1, -2, -2, 0, 0, null, null];
const uniqueArray = _.uniq(arr);

  JavaScript:   

const arr = [1, 2, 3, 'apple', 'orange', 4, -1, -2, -2, 0, 0, null, null];
const uniqueArray = [...new Set(arr)];

Expected Output:   

[1, 2, 3, 'apple', 'orange', 4, -1, -2, 0, null]   

_.find()

The find function is one of the most commonly and frequently used functions. As the name shows, it is used to find an element in a group of data. We use this function to obtain the primary object within the series, provided it satisfies the condition we set.

Lodash:   

const emp_data = [
{ emp_id: 201, location: "Germany" },
{ emp_id: 202, location: "Spain" },
{ emp_id: 203, location: "Italy" },
{ emp_id: 204, location: "France" }
];
const foundObject = _.find(emp_data, { location: "Italy" });   

JavaScript:   

const emp_data = [
{ emp_id: 201, location: "Germany" },
{ emp_id: 202, location: "Spain" },
{ emp_id: 203, location: "Italy" },
{ emp_id: 204, location: "France" }
];
const foundObject = emp_data.find(obj => obj.location === "Italy");

Expected Output:   

{ emp_id: 203, location: "Italy" }

_.filter()

The filter function is very similar to the find function that we mentioned earlier. This function also gives results by filtering all elements based on the condition we provide. We can get all of the elements from a group that satisfies our precise condition. We will follow the below example for the filter function.

Lodash:  

const filteredData = _.filter(emp_data, { location: "Italy" });  

JavaScript:   

const filteredData = emp_data.filter(obj => obj.location === "Italy");   

Expected Output:   

[{ emp_id: 203, location: "Italy" }]

_.every()

Every function is a conditional function that acts as a scanner for all of the elements. We provide an operational condition, and this function tests and offers a result (either True or False) of all the elements that satisfy the condition.

We will comply with the sample data for the emp_data example:

Lodash:   

const isEveryLocationFrance = _.every(emp_data, { location: "France" });   

JavaScript:   

const isEveryLocationFrance = emp_data.every(obj => obj.location === "France");   

Expected Output:   

false

_.some()

We can see the _.some function as a selective version of the _.every function. We offer an operational condition, and this function tests and offers a result (either True or False) if at least one of the elements inside the array adheres to the condition.

Lodash:    

const isSomeLocationFrance = _.some(emp_data, { location: "France" });  

JavaScript:    

const isSomeLocationFrance = emp_data.some(obj => obj.location === "France");

 Expected Output:    

true

_.includes()

This function is useful to check whether or not a selected element exists within the collection. This function accepts string data as well as array data.

We will comply with the same emp_data for reference:

Lodash:    

const includesItaly = _.includes(emp_data, { location: "Italy" });

 JavaScript:    

const includesItaly = emp_data.some(obj => obj.location === "Italy");    

Expected Output:    

true

_.flatten()

If we need to bring a nested array to the same level, then we can do this using a JavaScript function with an equal name (flatten) rather than the Lodash function.

Lodash: 

const nestedArray = [10, 20, [30, [40]], 50];
const flattenedArray = _.flatten(nestedArray);

 JavaScript:  

const nestedArray = [10, 20, [30, [40]], 50];
const flattenedArray = nestedArray.flat(Infinity);   

Expected Output: 

[10, 20, 30, 40, 50]

_.difference()

We can use JavaScript to get the difference between two different arrays. Lodash has a described method to get the difference, but in JavaScript, we use the filter and include methods to get the difference.

Lodash:

const array1 = [1, 2, 3, 4, 5];
const array2 = [3, 4, 5, 6, 7];
const diffArray = _.difference(array1, array2);

JavaScript:

const array1 = [1, 2, 3, 4, 5];
const array2 = [3, 4, 5, 6, 7];
const diffArray = array1.filter(value => !array2.includes(value));

Expected Output:

[1, 2]

Conclusion

Lodash or JavaScript native functions?; Source: GitHub

Ultimately, the choice between using Lodash or relying on native JavaScript functions depends on the particular necessities of the project and the developer's needs. As with most matters, writing better JavaScript is a non-stop process. Code can always be cleaner, new functions are added all the time, and there are never enough tests. It may also appear overwhelming, but because there are so many potential parts to improve, you can definitely improve at your own pace. Take matters one step at a time, and before you know it, you'll be a JavaScript ace.