Subscribe to my email list now at http://jauyeung.net/subscribe/
Follow me on Twitter at https://twitter.com/AuMayeung
Many more articles at https://medium.com/@hohanga
Even more articles at http://thewebdev.info/
With the release of ES6 and later versions of JavaScript, there were lots of methods released with it, expanding the functionality of the language. For example, there are new array and string methods, as well as useful operators like the spread and rest operators.
However, JavaScript still doesn’t make utility libraries like Lodash obsolete because there are lots of useful methods that still aren’t available in JavaScript.
In this article, we’ll look at a few methods from Lodash that still makes development easier than with plain JavaScript, including the times
, get
, set
, debounce
, deburr
, and keyBy
methods.
_.times
The times
method lets us call a function multiple times, put all the retuned results of each function call into an array, and return it.
It takes 2 arguments, which are the number of times that the function is called and the second is the function to call.
For example, we can use it as follows:
import * as _ from "lodash";
const getRandomInteger = () => Math.round(Math.random() * 100);
let result = _.times(5, getRandomInteger);
console.log(result);
Then we may get the following result:
[16, 83, 35, 87, 41]
_.debounce
We can use the debounce
method to delay a call of a function by a specified amount of time. There’s no easy way to do this with JavaScript.
This is useful for event handling where we want to wait for something to be done and then call a function. For example, with a typeahead search, a debounce would wait until the user is finished typing before making the API call, removing unnecessary hits on your server.
For example, we can use it as follows. Given the following number input:
<input type="number" />
We can write the following JavaScript code:
import * as _ from "lodash";
const checkPositiveNumber = e => {
console.log(+e.target.value > 0);
};
const numInput = document.querySelector("input[type=number]");
numInput.addEventListener("input", _.debounce(checkPositiveNumber, 600));
The code above has the checkPositiveNumber
function that checks if the value entered is positive. Then we use the debounce
method, which takes the function and the delay before calling it in milliseconds.
The function returned by debouce
has the same parameters and content as the original function, except that it’s delayed by the given number of milliseconds before calling it.
_.get
The get
method lets us access the properties of an object in a safe way. That is, even if the path to the properties doesn’t exist, it will return undefined
or a default value instead of crashing the program.
For example, given the following object:
const obj = {
foo: {
bar: { baz: { a: 3 } },
foo: { b: 2 },
baz: [1, 2, 3]
}
};
We can access obj
's property as follows:
const result = _.get(obj, "foo.bar.baz.a", 1);
The first argument is the object we want to access a property’s value. The second is the path to the property. The last argument is the default value.
We should get 3 for result
.
On the other hand, if the path doesn’t exist or it’s undefined
, then we get undefined
or a default value returned.
For example, if we have:
const result = _.get(obj, "foo.bar.a", 1);
Then we get 1 for result
.
If we don’t specify a default value as follows:
const result = _.get(obj, "foo.bar.a");
Then we get undefined
.
There’s no way to safely get the value of a deeply nested property until the optional chaining operator becomes mainstream.
_.set
There’s also a set
method to assign a value to a property of an object. For example, given the same object we had before:
const obj = {
foo: {
bar: { baz: { a: 3 } },
foo: { b: 2 },
baz: [1, 2, 3]
}
};
We can set a value to a property by writing:
_.set(obj, "foo.bar.a", 1);
The obj
object is changed in place. As we can see, it can set values for properties that don’t exist yet. The original object didn’t have foo.bar.a
and it added it automatically set the value to 1.
So we get:
{
"foo": {
"bar": {
"baz": {
"a": 3
},
"a": 1
},
"foo": {
"b": 2
},
"baz": [
1,
2,
3
]
}
}
It even works if the nested object doesn’t exist, so if we write:
_.set(obj, "foo.foofoo.bar.a.b", 1);
We get:
{
"foo": {
"bar": {
"baz": {
"a": 3
}
},
"foo": {
"b": 2
},
"baz": [
1,
2,
3
],
"foofoo": {
"bar": {
"a": {
"b": 1
}
}
}
}
}
_.deburr
To remove accents from characters with strings, we can use the deburr
method. It takes in a string and returns a new string with the characters that have accents replaced with the ones that don’t have them.
For example, if we have “S’il vous plaît”
:
const result = _.deburr("S'il vous plaît");
Then we get that result
is "S’il vous plait"
. The ‘i’ no longer has the accent.
_.keyBy
The keyBy
method takes an array and the property name and returns an object with the value of the property as the keys of the object.
For example, if we have the following array:
const people = [
{ name: "Joe", age: 20 },
{ name: "Jane", age: 18 },
{ name: "Mary", age: 20 }
];
Then we can use keyBy
as follows:
const results = _.keyBy(people, "name");
Then results
would have the following:
{
"Joe": {
"name": "Joe",
"age": 20
},
"Jane": {
"name": "Jane",
"age": 18
},
"Mary": {
"name": "Mary",
"age": 20
}
}
Then we get the object with name 'Joe'
by writing:
results['Joe']
There’s no way to do this easily with plain JavaScript without writing multiple lines of code.
Conclusion
Lodash has many useful functions that don’t have an equivalent that are as easy to use as these methods.
There’s the times
method to call a function multiple times in one line. The debounce
function returns a new function with the same signature and code as the original but it’s delayed by the given amount of milliseconds before it’s called.
For accessing and setting object properties and values safely, there are the get
and set
methods that don’t crash when we access property paths that don’t exist or has value undefined
.
Then there’s the deburr
method to replace accented characters with the non-accented versions of these characters.
Finally, there’s keyBy
method to get massage an array into an object that has the given property’s value of each entry as the keys and the entry with the given property’s name’s values as the value of those keys.
Top comments (16)
To do the same with ES methods, just the first two examples:
_.times
_.debounce
These two example illustrate well that some things are easier to achieve without lodash than others. For me, the rule of thumb is: if I use a lodash method, I use it separately (never import all of it, and if possible, use the es version that can be tree-shaked!) and make sure I reuse it throughout the code so I actually get something in return.
In a surprisingly lot of cases I have seen, the use of utilities like lodash means outsourcing the deeper understanding of a problem to a library. While that can help speed up development in the short term, it might become a convenient habit, so much that one is tempted to overcomplicate the issue at hand in order to use these utilities when it could have been far simpler solved with native methods.
That does not mean you should not use lodash, but you should be conscientious about the implications.
This.
It makes me unsure if I should use
lodash.clonedeep
orlodash.merge
... If I write it myself, I can be sure of the implications.Also, lodash is too magical and too widely accepting in some methods, such as
lodash.filter
. (I saw a lot in lowdb.)A very nice example is
_.isEmpty()
: in most cases, you are testing if an object has no enumerable keys. You'll rarely need to check at the same time if the length of an array or a string is zero, but lodash will (needlessly in the stated case) check the input for all available types.This is one of the ones that we can implement ourselves without much effort.
I think the array's built-in
filter
method is pretty good so I never want to use the Lodash version.The problem with all the examples is
That'll pull in the entire lib. At this point, if you're looking for a utility, it should be very selective, much like your article suggests. That means your
npm install
should only pull in that utility, not the whole library.You're right. Just import the methods you need to use. That's more efficient.
Someone in another component has already shown how to implement
times
anddebounce
.Get can be achived with optional chaining, so heres how to dokeyBy
:...and with types:
(Have't tested this since I'm on mobile rigut now, but you yet the idea)
Conclusion
Since its doable in 1 line your statemet kinda false
To avoid
Object.fromEntries
, there is.reduce
.Actually, with map, filter, reduce -- you can do a lot.
It is impossible to say that you cannot do something in one-liner JavaScript, because minified JS is also a one liner.
I agree. I think there're things like
differenceWith
in Lodash that are harder to implement by ourselves and not available in the standard library.Can’t you now using optional chaining instead of
_get()
I'm not sure if it's finalized yet, but hopefully, it will be soon so that we don't need Lodash for it.
Thanks for the post, John! I'll admit, Lodash always felt "dirty" to me, especially since so many of its methods are now part of the ECMA standard or can be implemented in a few lines of native JavaScript. But the ones you highlighted are still very useful.
It's useful if you don't want to create your own function to do the things it does.
Very helpful! Thanks for sharing this worthy information.
Thanks for reading