This article was written by Ryan Thelin and was originally published on Educative.
So, you have a handle on writing JavaScript, but how do you go from practice to real problem solutions? How do you alter your JS code to make it simpler and easier to read? If you work on a team, it's important to write simple code. Since you're not working in a vacuum, your programs must be easy to follow by your team members. Everyone loves clean code! Learning how to make JavaScript as painless as possible is an invaluable skill sure to make you an office favorite.
Let's go over 15 best practice tips to help simplify your JavaScript and make it easily understandable by other developers. Here's what we'll cover.
- Declare and initialize your variables at the top
- Build modular, specialized Functions
- Recognize and remove duplicate code
- Comment your code often
- Beware of recursion overuse
- Be efficient with DOM manipulations
- Avoid global variables at all costs
- Make use of shorthand notation (object literals)
- Use Strict Mode to catch silent errors
- Set default values
- Use template literals to combine strings
- Solve existence testing with
includes
- Shorten conditionals with false values
- Sharing methods with inheritance
- Write shorter loops with array methods
- Wrapping up and resources
Looking for an advanced guide to simplifying your code? Check out our course Simplifying JavaScript for hands-on practice.
1. Declare and initialize your variables at the top
Nothing disrupts readability like a late declaration. Just as it's easier to take out all your tools before starting a job, it's simpler to declare all variables before getting into the nitty-gritty of your function. This gives easy access should we need to tweak any name or value later down the line.
While on the topic of variables, it's best practice to initialize your variables at the time of creation so you and your team can ensure none are left undefined
.
<script>
var x = 5;
</script>
2. Build modular, specialized functions
No one function should have to do it all, for both efficiency and readability's sake. Instead, when designing functions, consider a single task that it should accomplish and write it to complete that task only. Name the function to match that task.
This makes the code easier for others to read. The function will inherently be simpler and less extensive if only working toward one task. Further, it allows you and your team to lift this function to another program should you need it later. Even with just the passed variable names and function titles, we get a clearer understanding of where to find certain tasks in the second version below.
function table (columns, rows, item){
creates table and searches it for the passed item
}
// compared to
function createTable (columns, rows){
//creates table
}
function searchTable (table.length, item) {
//searches table for the passed item
}
3. Recognize and remove duplicate code
Similar to our last example, you should look out for instances in your code where you have identical lines of duplicate code. In cases like these, you should move the duplicated code into a function and call the function in all the instances that it was used before. This reduces visual clutter and aids in debugging later as the team can look at the one function rather than its multiple usage sections.
<script>
var x = 5;
var y = 6;
var x = x*2
var y = y*2
</script>
<script>
var x = 5;
var y = 6;
function double (value){
return value*2;
}
double (x);
double(y);
</script>
4. Comment your code often
Comments are a great way to summarize a code fragment's purpose, saving your fellow developers the time it would take to determine it on their own. It also allows them to catch possible mistakes if the code does not complete the task it is commented to complete. In general, it's best to leave one comment on every function. If you're unsure if you should leave a comment, just do it! It can always be deleted later if it's too much clutter.
//declares and initializes var x
<script>
var x = 5;
</script>
5. Beware of recursion overuse
Be mindful of nesting recursive functions too many levels. While capable of solving many problems, nesting is notoriously difficult to understand at a glance.
To avoid confusion, be mindful of where recursive functions can be pulled out of their nested place without significant runtime cost and do so whenever possible. If you have 3+ levels of nested functions, chances are your fellow developers will have a hard time following it.
function1 (a,b){
function2{
function3{
//this is too hard to follow and can likely be solved another way
}
}
}
</script>
6. Be efficient with DOM manipulations
Accessing the DOM is essential for getting the most out of your program, but doing so repeatedly causes visual clutter and will slow down the program. Instead, access it once and cache it for later use in a variable. From then on, you can access that variable instead of the DOM directly. This process is visually cleaner and more efficient.
Note: When referencing DOM variables, it is standard practice to denote it using
$
.
function accountInfo(){
var email = $("#accounts").find(".email").val();
var accountNumber = $("#accounts").find(".accountNumber").val();
}
// Contents cached to variable "accounts"
function accountInfo(){ var $accounts = $("#accounts");
var name = $accounts.find(".email").val();
var age = $accounts.find(".accountNumber").val();
}
7. Avoid global variables at all costs
In JavaScript, variables have a scope in which they can be used, either global or local.
These scopes decide where in your code these variables are defined or can be accessed.
Global variables can be defined anywhere in the program and exist outside of functions.
Local variables are only visible within the function it is defined.
If there are a local variable and a global variable with the same name, JavaScript will prioritize the local variable and ignore the global variable.
Global variables should still be avoided, as they can accidentally overwrite window variables resulting in errors. Further, having many global variables will slow down your program since they are not deleted until the window is closed, whereas local variables are deleted once the function is completed.
<html>
<script>
var myVar = "my global variable"; // This variable is declared as global
function localVariable( ) {
var myVar = "my local variable"; // This is a locally declared variable
</script>
</body>
</html>
8. Make use of shorthand notation (Object Literals)
When designing objects or arrays in JavaScript, line space can be saved by opting for shorthand notation. This is accomplished by setting the properties or cells of an object or array during declaration rather than after. This saves you having to identify which object or array you're setting for on each line, making the section easier to read. While this may seem like a small change, it can save a lot of eye strain for your team as the objects and arrays get more complex.
Longhand Object:
var computer = new Object();
computer.caseColor = 'black';
computer.brand = 'Dell';
computer.value = 1200;
computer.onSale = true;
Shorthand Object:
var computer = {
caseColor: 'black';
brand: 'Dell';
value: 1200;
onSale: true;
}
Shorthand Array:
var computerBrands = [
'Dell',
'Apple',
'Lenovo',
'HP',
'Toshiba',
'Sony'
];
9. Use Strict Mode to catch silent errors
JavaScript is a very forgiving language compared to other hardcoded languages like C++ and Java. While helpful for getting code to run without throwing errors, this leniency can lead to silent errors that pass without correction. This can also lead to inconsistent behavior if JavaScript can resolve the silent error in multiple ways.
To bypass this, opt into Strict Mode. This setting makes two major changes:
- Silent errors that would previously make it past the compiler now throw errors, allowing you to fine-tune your code before it reaches your team members.
- Fixes mistakes that prevent JavaScript from optimizing your code
- JavaScript Strict Code programs often run faster than their "sloppy" counterparts
To opt into strict mode, add the line'use strict';
either at the top of your script section (if you want the whole section to be strict) or before the desired function (if only certain sections should be strict).
10. Set default values
When creating objects, you can set default values for some or all properties of the object. Doing so ensures the values of each attribute are not undefined
. It also demonstrates what type of data is expected for that attribute. Additionally, by not setting default values for certain properties, you can communicate to your team that those values are not required for the object to function correctly.
function logProperty({
address = '111 11th Street, 11111',
unit, //optional
landlord = 'Sara',
tenant = 'Raj',
rent = 500,
})
Above, not all properties will have a unit number, but all will have the other four properties, which are populated with the data type expected. To demonstrate this, we leave unit
blank.
Keep the learning going.
Learn how to write clean JavaScript code without scrubbing through videos or documentation. Pragmatic Programmers has compiled 51 real-world tips for JS coders. Educative's text-based courses are easy to skim and feature live coding environments - making learning quick and efficient.
Simplifying JavaScript: A Handy Guide for Software Engineers
11. Use template literals to combine strings
Putting strings together is a pain, especially when combining strings and variables. To make this process simpler, you can use template literals (marked by backticks), which take both a string and variable.
function greet(name) {
return `Hi, ${name}`; //template literal
}
console.log(greet('Leo'));
Notice here that by using the template literal, we can log a greeting to any user based on the name passed to us, combining the string Hi,
and the value of the passed variable name
.
This code therefore prints:
Hi, Leo
12. Solve existence testing with includes
Testing the existence of a value within an array is a common problem. Thankfully, JavaScript comes with a special array method, includes()
, which will return a Boolean if the array contains the searched value. Rather than searching the array, this method provides an efficient, easy-to-read solution.
const sections = ['contact', 'shipping'];
function displayShipping(sections) {
return sections.includes('shipping');
}
console.log(displayShipping(sections));
In the full course from Pragmatic Programmers, you'll also learn how to use the indexOf()
method to check a value and to find its index as well!
13. Shorten conditionals with falsy values
In JavaScript, there are many values that are equivalent to false
across multiple types of variables. This includes:
- the Boolean
false
null
0
-
NaN
(not a number) ' '
" "
In JavaScript, equivalent ==
means that the two objects share the same values, but they may not be the same type. Identical ===
means that the two objects are both the same type and same value.
But how is this useful?
Well, instead of creating separate variables to hold Booleans, you can instead use the above as default values to report false
if nothing overwrites it. Consider this example, you need to check if a given employee has equipment training (equipmentTraining
). This machine only requires the lowest level of training, the level of training is unimportant.
As a result, our if
statement checks if equipmentTraining
still has a falsy value, the default ' '
. If it does, the if
statement executes and returns that the employee is not authorized. If equipmentTraining
contains any string other than the default, it will have a truthy value and therefore not execute the if
statement.
const employee = {
name: 'Eric',
equipmentTraining: '',
}
if (!employee.equipmentTraining) {
console.log('Not authorized to operate machinery');
}
14. Sharing methods with inheritance
Inheritance concerns a way of sharing properties or methods between classes. This is done using the super
tag to allow the constructor in FlashCoupon
to access the parent constructor in Coupon
. In doing so, you enhance the readability of your code by only defining the methods once (in the parent class). This makes your code to be more modular since inheritor classes can be specialized for a given task.
Notice that the top code box establishes a parent class, Coupon
, the properties and methods of which are shared to FlashCoupon
as seen by FlashCoupon
calling the getExpirationMessage
method on its final line.
class Coupon {
constructor(price, expiration) {
this.price = price;
this.expiration = expiration || 'Two Weeks';
}
getExpirationMessage() {
return `This offer expires in ${this.expiration}`;
}
}
export default Coupon;
import Coupon from './extend';
class FlashCoupon extends Coupon {
constructor(price, expiration) {
super(price);
this.expiration = expiration || 'two hours';
}
}
const flash = new FlashCoupon(10);
console.log(flash.getExpirationMessage());
15. Write shorter loops with array methods
For our final tip, we'll dive into the complexity of array optimization. Loops are a common way to create and populate arrays. However, they cause a lot of clutter and can be hard to read due to the number of lines required. Instead, you can use array methods to accomplish similar effects as for
loops with only a fraction of the lines.
Take this for
loop for example.
const prices = ['1.0', 'negotiable', '2.15'];
const formattedPrices = [];
for (let i = 0; i < prices.length; i++) {
const price = parseFloat(prices[i]);
if (price) {
formattedPrices.push(price);
}
}
console.log(formattedPrices);
Instead of the above code, we can get the same effect from three lines below by making use of the map
method. This method creates an equivalently sized array with only the prices
property. We then get float values of that price using the parseFloat
.
const prices = ['1.0', '2.15'];
const formattedPrices = prices.map(price => parseFloat(price));
console.log(formattedPrices)
Wrapping up and resources
The quest for cleaner code is an ongoing journey since best practices are constantly evolving with the language. This process is part of the fun of software development, and learning best practices demonstrates true mastery over a programming language.
To get a great head start on learning more best practices and tricks to simplify your JavaScript code, check out Pragmatic Programmer's extensive, hands-on course Simplifying JavaScript: A Handy Guide for Software Engineers. By the end, you'll be a productive, modern JavaScript developer.
Top comments (2)
+1 for writing specialized functions
I wrote some very specific functions, like a year ago. then we went through major refactors but the functions are still there and serve the same purpose.
Although declaring variables are somewhat subjective, some languages like python, recommend to initialize variable when you need them.
useful.. thanks for sharing !