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/
Functions are important parts of JavaScript programs. They are used for dividing code up into reusable chunks. Therefore in order to have clean JavaScript code, we have to have easy to understand functions.
In this article, we’ll look at more characteristics of good functions, including reducing the use of switch statements, reducing the number of parameters in our functions, and getting arguments in an easy to understand way.
Switch Statements
switch
statements are always long even if they have only a few cases. Therefore, they should be used in a way that’s never repeated by separating into a function that can be invoked wherever is needed.
An example of a bad switch
statement would be something like the following code:
const calculatePay = (employeeType) => {
switch (employeeType) {
case 'PART_TIME':
return calculatePartTimePay();
case 'FULL_TIME':
return calculateFullTimePay();
case 'COMMISSIONED':
return calculateContracorPay();
default:
return 0;
}
}
The code above is long and it does more than one thing. It’s better to just skip the switch
statement and then call them wherever they’re needed.
Also, we have to change this function every time we change the type.
Another problem is that we’ll have many other functions with this structure, which means the code will get longer and have more functions with the same problems as this one.
To deal with this, we can return the correct object for the type of employee that we want. For example, we can write instead:
const getEmployeeObjectByType = (employeeType) => {
switch (employeeType) {
case PART_TIME:
return new PartTimeEmployee();
case FULL_TIME:
return new FullTimeEmployee();
case CONTRACTOR:
return new ComissionedEmployee();
default:
return undefined;
}
}
And then we can just call this function to get the right type of employee and then do what we want with it.
It’s much better than having multiple functions with the same switch statement cases doing different things.
Descriptive Names
Like any other identifier in our code, the names in functions should be descriptive like everything else.
They should be named with names that tell what they mean. Information like the meaning, intent, and action should be conveyed from the code.
The type may also be helpful in some cases if the type of something isn’t immediately clear from looking at the code since JavaScript is a dynamically typed language.
Longer names are OK is they’re needed to convey all the information that we need to know. They can still be easy to read if they follow JavaScript’s convention, which is to use camel case for variables and non-constructor functions, upper case for constants, and upper camel case for constructor functions.
Function Arguments
Functions should have as few parameters as possible. This is because we have to look at all of them and when we call them, we have to make sure that they’re all passed in.
Therefore, if we don’t need parameters, then we shouldn’t include them. Zero is better than one and one is better than 2.
More than 5 is probably too much unless there’s some special reason for it.
Passing in arguments is hard since we have to gather all the variables and values and pass them in. Likewise, it makes testing harder for the same reason.
When we test a function with lots of arguments, we’ve to test all the possible combinations of arguments to get full test coverage. This makes testing a function that takes lots of arguments many times harder than ones that take fewer arguments.
Also, with the rest operator being a standard feature in JavaScript, it’s time to abandon the arguments
object if we need to define a function with lots of arguments. It’s an array-like object so it has some property of arrays, like indexes and the length
property.
We can also loop through it with a for
or a while
loop. However, it doesn’t have any array methods that are part of a normal array.
Like other array-like objects, it can be spread with the spread operator.
They just create confusion for lots of people since many people aren’t familiar with the arguments
object.
The arguments
object also doesn’t bind to arrow functions, so we can’t use it with them.
With the rest operator, we get an array of arguments returned from it, so we can do everything that we can do with arrays.
So instead of writing:
function add() {
return [...arguments].reduce((a, b) => a + b, 0);
}
We should write:
function add(...args) {
return args.reduce((a, b) => a + b, 0);
}
To make a function that adds some numbers together. Or better yet:
const add = (...args) => {
return args.reduce((a, b) => a + b, 0);
}
since we aren’t using this
in our code.
As we can see, the 2 later examples with the rest operator are much clearer than the first one. The first one has no parameters in the signature and yet we’re getting the arguments passed in from the arguments
object.
The other 2 shows that our add
function actually takes arguments and we’re actually doing something with them.
Conclusion
Functions might look easy to define on the surface, but to define functions that are easy to read and change, we have to do it with care. We should avoid having too many switch
statements.
If we do need them, we should abstract them so that one switch
statement can be used in multiple places. They’re long and should be minimized.
Also, the names of things inside a function should be descriptive, and we should never take too many arguments in our functions. If we do, use the rest operator instead of the arguments
object to get the arguments passed into our functions.
The post JavaScript Clean Code — Function Arguments appeared first on The Web Dev.