I am going to show you 3 simple JavaScript changes that I think will improve your code.
1. Pure Functions
What do I mean by this? Well not quite the strict pure function definition but what I like to aim for is; a function that takes in arguments and returns a value. Ideally there should be no side effects from a pure function but sometimes that is easier said than done.
///trivial example
function add(a,b){
return a+b;
}
This example is pretty straight for. Take in two values and return a value, really simple.
//Don't do this
function badProcessPerson(person){
person.fullName = `${person.firstName} ${person.lastName}`;
person.shoeSize = person.showSize || 7;
}
This is a common issue and one immutability also aims to solve but that is a topic for another day. By passing in a reference type any changes made to the object will be reflected outside of the function. However if we explicitly return the modified object the consumer of the function will be certain they have the necessary changes.
//Do this
function goodProcessPerson(person){
person.fullName = `${person.firstName} ${person.lastName}`;
person.shoeSize = person.showSize || 7;
return person
}
//but ideally this
function goodProcessPerson(person){
return {
...person,
fullName: `${person.firstName} ${person.lastName}`,
shoeSize:person.showSize || 7
}
}
Multiple returns?
If you need to return multiple values consider using an object to encapsulate the values. With object de-structuring, consuming the results has gotten even easier.
const {total, avg} = getTotalAndAverage(scores);
2. Parameter Order
When creating functions I always try and make the data that is being acted upon the last argument.
// Don't do this
function setAge(user, age){....
// Do this
function setAge(age,user){
This practice really lends itself to some examples below...
3. Currying
Currying allows us to partially apply a function, only executing once all the arguments have been received. Whilst there are many frameworks out there with currying functionality you can also achieve similar results with this little gem:
const setAge = (age) => (user) => {....
setAge(24)(currentUser);
HOORAY for arrow functions!!
Now let me clear this is NOT true currying but it allows us to quickly create a function that we can partially apply.
Tying them together
Array Functions
Array functions are great but take a look at the following example:
const users = [...];
const olderThan = (user,age) => user.age > age;
const over18 = users.filter(x => olderThan(x, 18));
Whilst this code is fine by reordering the parameters and currying the function it becomes a lot more readable.
const users = [...];
const olderThan = age => user => user.age > age;
const over18 = users.filter(olderThan(18));
Promises
Just like Array functions benefited from curried, pure functions with nicely ordered parameters, Promises can as well. Let's take the function from the previous code and build upon it.
const olderThan = age => user => user.age > age;
const filterUsers = filterFn => users => users.filter(filterFn);
const over18 = getUsers().then(filterUsers(olderThan(18)));
Conclusions
These changes aren't ground breaking but I do think they have a few important benefits. Pure functions are super easy to test and always returning a value can help alleviate accidentally updating reference type. Combine that with currying and good parameter order and you end up with functions that produce easier to read code when interacting with Arrays and Promises.
What's a simple code change you think makes a big impact on a code base?
Top comments (4)
Love the article, some tips I had never really thought of and will try to implement more in my day to day.
My only question is around the currying. You mention partially applying a function and only executing only all the arguments are received. I may be wrong but couldn't this be achieved using async / await functions?
I am glad you liked the article!
Whilst you could use async/await I would recommend not using Promises unless the action is truly asynchronous as it introduces overhead that is not necessary. I would recommend digging around the ramda library on github to see how the implement their curry. github.com/ramda/ramda/blob/master...
I suppose this something I haven't thought about, I just assumed promises would be efficient but I guess they do add overhead to the code having to wait and keeping checkung.
Thanks for pointing it, I'll check out that library and see how they do it.
You won an unicorn here due to the currying example. This kind of quality is really needed in Javascript post :)