Improving JavaScript code: top 6 best practices

The world of frontend development is rapidly changing, new libraries and frameworks are appearing, and the development process is improving and simplifying. It is very difficult to keep up with all the innovations.

We’ve gathered 6 relatively new lifehacks that will improve your code in JavaScript.

Optional Sequences
To access the properties of nested objects, even if some of them are missing, you can use option sequences. This is a new feature, so you’ll need to use polyfil to access it in older browsers.

Option sequences – make code cleaner and shorter. They allow you to quickly detect the absence of a property without having to manually search for it. In addition, they do not remove the exception, but return it as undefined.

Example:

const someObject = {
	profile: {
		firstName: 'Nicky',
		lastName: 'Christensen',
		country: 'Denmark'
	}
}

// Example 1 // with optional sequences:
if (someObject?.profile?.firstName){
	console.log('Name is 1: ', someObject.profile.firstName)
} // safe navigation through the object graph

// Example 2 // the old way without optional sequences:
if (someObject && someObject.profile && someObject.profile.firstName){
	console.log('Name is 2: ', someObject.profile.firstName)
}

// optional chains do not work because name does not exist:
if (someObject?.profile?.name){
	console.log('Name is 3: ', someObject.profile.firstName)
}// safe navigation through the object graph

Conclusion: Example 1 outputs only 2 console.log() in the form of Name is 1 and Name is 2, but Name is 3 does not, because it is absent in the profile.

In Example 2 without using optional sequences, you can see that the code is larger and more complex.

Zero merge operator
In cases when the ||| operator is used to set the standard value of the foo variable and false-like objects are considered appropriate – there is a risk of incorrect behavior. To avoid such situations, the null merge operator ?? appeared. It refers to logical operators that return the value of the right operand if the left operand contains null, undefined or any other false-like value. Under other conditions, it simply outputs the value of the left operand.

Example:

const falsy = false;
const emptyString = '';
const nullish = null;
const uDefined = undefined;
console.log('1', falsy ?? 'Some string');
console.log('2', emptyString ?? 'Default string')
console.log('3', nullish ?? 'Default string')
console.log('4', uDefined ?? 'Default string')
console.log('-------');
console.log('1.1', falsy || 'Some string');
console.log('2.2', emptyString || 'Default string')
console.log('3.3', nullish || 'Default string')
console.log('4.4', uDefined || 'Default string')

Dynamic Import
ECMAScript introduced a more convenient dynamic import. Unlike static import, it loads modules asynchronously. A similar principle of code splitting has long been used with build tools. At the same time, dynamic import does not require specific scripts and works without writing script type=”module”.

Example:

let someAsyncModule = await import('/modules/my-module.ts');

Promise.allSettled()
The familiar Promise.all() proved itself as a method of returning all promises. But it did not show which ones were executed and which ones were not. The more modern Promise.allSettled()method returns only those promises that are completed, but leaves an array of all others for further action.

Example:

const promise1 = Promise.resolve("OK, I resolved");
const promise2 = Promise.reject("OH no, I was rejected");
const promise3 = Promise.resolve("After I was rejected");
Promise.allSettled([promise1, promise2, promise3])
	.then((results) => console.log(results))
	.catch((err) => console.log("error: " + err));

Spread operators
The twin of the rest operator is spread. It has the same syntax, but it is aimed at combining objects and arrays. Earlier its function was performed by array.concat, but spread is more convenient and easy to use. It stretches elements rather than collapsing them. It is also used to copy arrays.

Example for arrays:

const arr1 = [1,2,3];
const arr2 = [4,5,6];
const arr3 = [...arr1, ...arr2] //arr3 ==> [1,2,3,4,5,6]

Example for objects:

const basePerson = {
	name: 'Nicky C',
	country: 'DK'
}
const footballerPerson = {
	...basePerson,
	team: 'Man UTD',
	shirtNumber: '11'
}
console.log(footballerPerson)

Object destructuring
Using the object destructuring syntax, you can extract the values you need and write them into new values with minimal code.

Example:

const basePerson = {
	name: 'Nicky C',
	country: 'DK'
}
const footballerPerson = {
	...basePerson,
	team: 'Man UTD',
	shirtNumber: '11'
}
const {team, shirtNumber} = footballerPerson;
console.log(team, shirtNumber); //ManUtd, 11