There are better ways to write JavaScript code than others.
In this article, we’ll look at the best practices for using the latest JavaScript syntax features.
Syntactic Sugar
In JavaScript, the syntactic sugar that’s included is usually good.
They let us write code in a shorter and clear way and make them more readable in the process.
These syntactic sugars are drop-in replacements for existing techniques so we should use them.
const Isn’t Consistent
const
is a keyword for declaring block-scoped constants.
They’ll make primitive values assigned to it immutable since we can’t assign a constant again after it’s assigned to a value.
A value must be assigned when we declare it.
However, const
is a bit deceptive since some people might not know that we can still change objects that are assigned to const
by changing their properties.
Also, arrays can be changed in place with methods like push
and unshift
.
Therefore, we shouldn’t assume that objects that are assigned to const
are immutable.
Limiting the Scope of the Function
Traditional functions defined with the functionm
keyword can be called to run statements defined in the block and may return a value.
They can be run anywhere if they’re written as a function declaration.
For instance, if we have:
function foo() {
//...
}
Then foo
can be run before or after it’s defined.
It also defines its own this
and can be used with the new
operator as a constructor.
So, to limit the capabilities of our functions, we should use arrow functions.
If we need constructors, then we should use the class syntax to define them to make everyone clear.
The Class Syntax
The class syntax is great for defining constructors. It does the same thing as the old constructor function syntax.
It looks like a class in an object-oriented language like Java, but it does the same thing as JavaScript constructors.
Therefore, the prototypical inheritance model is still used with JavaScript classes.
So the following:
function Person(name) {
this.name = name;
};
Person.prototype.greet = function() {
console.log(`hi ${this.name}`);
};
is the same as:
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`hi ${this.name}`);
}
}
They hold and do the same thing but the placement of the fields and methods are different.
Arrow Functions
Arrow functions are great. They are shorter. Thet but more neatly in callbacks.
It can return without adding the return
keyword if we return in the first line.
They encapsulate qualities that make them more convenient. But they aren’t a drop-in replacement for traditional functions defined with the function
keyword.
We can call bind
by to change this
inside a function.
Also, we can’t call call
and apply
with them to change this
and call functions with arguments with them.
Going Asynchronous
Going async with JavaScript has its own difficulty because of JavaScript’s single-threaded nature.
We’ve to write code that unblocks the thread so that they won’t hold up our programs until we’re ready to run them.
This is where async code with callbacks come in to make calling async code easier.
We can make our code async by calling setTimeout
. Also, pretty much any HTTP client runs in an async manner.
If we have lots of async code with callbacks, then we have to nest callbacks.
This gets ugly real fast.
If we use callbacks for chaining async code, we may have code that looks like this:
async1((err, res) => {
if (!err) {
async2(res, (err, res) => {
if (!err) {
async3(res, (err, res) => {
//...
});
}
});
}
});
That’s ugly and just not maintainable. Instead, we use promises. Then we can write something like:
promise1
.then((res) => {
//...
return promise2
})
.then((res) => {
//...
return promise3
})
.then((res) => {
//...
})
That’s much cleaner than nesting async callbacks with the previous example.
We can make things even shorter by writing:
(async () => {
const val1 = await promise1;
//...
const val2 = await promise2;
//...
const val3 = await promise3;
//...
})();
As we can see, the code is much shorter and it’s exactly the same as the promise chain we have before.
The only difference is that va11
, val2
, and val3
hold the resolved values of the promises instead of res
.
Conclusion
We got to know some things about JavaScript like how const
aren’t always immutable, and clean up async code with async
and await
.
Also, arrow functions and classes should be used for regular functions and constructors respectively.