In this article, we will look at how to write JavaScript code using some handy shorthands that make our code cleaner and easier to read.
JavaScript is a popular programming language for developing web applications and more. It has grown from a language used for creating simple scripts to make webpages to a dynamic one that can be used to create many programs.
We can make our JavaScript code cleaner by using some easy-to-read shorthands to do various operations—and that is what we will look at in this article.
The ternary operator lets us return a value if a condition is true and return a different value otherwise.
We can write an expression with it by writing a boolean expression, followed by ?
, the value to return when the boolean expression returns a truthy value, :
and the value returned when
the boolean expression returns a falsy value.
For instance, we use it by writing:
const foo = true;
const bar = foo ? "heads" : "tails";
console.log(bar);
to return “heads” if foo
returns a truthy value and “tails” otherwise.
As a result, bar
is heads
since foo
is true
, which is truthy.
This is the shorthand for it:
const foo = true;
let bar;
if (foo) {
bar = "heads";
} else {
bar = "tails";
}
console.log(bar);
As we can see, we simplified our code by replacing the if-else statements with a ternary expression.
We also avoided using let
which is better since we won’t have to worry about reassigning a const
variable to a new value by accident.
The optional chaining operator lets us get properties that are deeply nested without worrying about any property in the chain not existing or having a non-object value.
The operator is denoted by ?.
.
For instance, we can use it by writing
const obj = {
foo: {
bar: {
baz: {
qux: 1,
},
},
},
};
console.log(obj?.foo?.bar?.baz?.qux);
Then 1 is logged in the console log since obj?.foo?.bar?.baz?.qux
property returns 1.
The benefit of this is that we don’t have to worry about any property in the chain not existing or having a non-object value.
For instance, we write:
const obj = {
foo: {
baz: {
qux: 1,
},
},
};
console.log(obj?.foo?.bar?.baz?.qux);
Then the console log logs undefined
since we no longer have the bar
property in the obj
object.
If we use the regular .
operator to access the same property, we will get the bar
property is undefined error since it doesn’t exist.
obj?.foo?.bar?.baz?.qux
is equivalent to obj && obj.foo && obj.foo.bar && obj.foo.bar.baz && obj.foo.bar.baz.qux
.
As we can see, the former expression is much shorter.
The optional chaining has been available since the ES2020 release.
The nullish coalescing operator is another operator that is introduced with ES2020.
It lets us return a fallback value if the value we want to return is null
or undefined
.
The operator is denoted by ??
.
For instance, we use it by writing:
const foo = null;
const bar = foo ?? "bar";
console.log(bar);
const baz = undefined;
const qux = baz ?? "baz";
console.log(qux);
const x = 1;
const y = x ?? 2;
console.log(y);
If the first operand is null
or undefined
, then the second operand’s value is returned.
Therefore, bar
is 'bar'
and qux
is 'baz'
. y
is 1 since x
is 1, which is not null
or undefined
.
If we want to check if an expression returns true
, we don’t have to check for true
with ===
.
Instead, we just put the expression in the if
statement.
For instance, instead of writing:
if (isHappy === true) {
//...
}
We write:
if (isHappy) {
//...
}
The first if
statement only checks if isHappy
is true
.
And the second if
statement checks if isHappy
, returning a truthy value.
Therefore, if isHappy
can return a truthy value other than true
, then we may want to change the first if
statement to check more precisely.
Since ES2015, JavaScript functions can have default parameter values.
For instance, we write:
const add = (a = 1, b = 2) => {
return a + b;
};
console.log(add(5, 6));
to set the default value of the a
parameter to 1 and the default value of b
to 2 in the add
function.
This lets us set a fallback value in case any parameter has no value set.
Default function parameters if shorthand for something like:
const add = (a, b) => {
if (!a) {
a = 1;
}
if (!b) {
b = -2;
}
return a + b;
};
console.log(add(5, 6));
where we assign a
and b
default values if they don’t have a truthy value.
As we can see, the first add
function is much shorter than the second because of the use of the default function parameters feature.
Default function parameters are short and easy to understand.
Oftentimes, we want to loop through every item in an array.
This can easily be done with the JavaScript for-of loop which has been available since ES2015.
We can use it by writing:
const arr = [1, 2, 3, 4, 5, 6];
for (const a of arr) {
console.log(a);
}
to loop through the entries in the arr
array with the for-of loop.
a
is the loop variable that has the current entry in arr
being looped through.
And we log the value of a
in the loop.
Therefore, we see:
1
2
3
4
5
6
in the console log.
This is shorter than using a regular for loop where we have to define an index variable and use it to access the entry being looped through like:
const arr = [1, 2, 3, 4, 5, 6];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
where i
is the index variable that’s incremented by 1 with each iteration until it reaches arr.length - 1
.
Another benefit of the for-of loop is that we can use it to iterate through any iterable object.
For instance, we write:
const set = new Set([1, 2, 1, 1, 4, 5, 6]);
for (const s of set) {
console.log(s);
}
to loop through the set
with the for-of loop.
s
has the entry being looped through.
Since sets discard any duplicate entries when they’re added, we get:
1
2
4
5
6
from the console log.
We can add properties to an object by setting the object property’s value to a variable’s value.
For instance, we write
const x = 1;
const y = 2;
const obj = {
x,
y,
};
console.log(obj);
to create the obj
object with properties x
and y
set to the values of variables x
and y
respectively.
As a result, we can see obj
's value is:
{
x: 1,
y: 2
}
This is short for:
const x = 1;
const y = 2;
const obj = {
x: x,
y: y,
};
console.log(obj);
We can eliminate the colon and the expression after that if the property name is the same as the property value’s variable name.
This has been available since ES2015.
JavaScript has the exponentiation operator (**
), which is equivalent to using the Math.pow
method.
The left operator is the base and the right operand is the exponent.
For instance, we write:
const x = 2 ** 3;
to return the value of 2 raised to the power of 3 and assign that to x
.
As a result x
is 8.
We can do the same thing by writing:
const x = Math.pow(2, 3);
But **
is shorter and doesn’t involve calling any functions we don’t need to call.
Arrow functions let us define functions without using the function
keyword.
It doesn’t bind to its own value of this
so we can’t use them as constructor functions, which may be good depending on why we want to define the function.
If we don’t want to create an instance of the constructor, then we can use arrow functions.
For instance, we write:
const add = (a, b) => {
return a + b;
};
console.log(add(1, 2));
to define the add
function.
As we can see, we defined a function without using the function
shorthand, which makes it shorter.
And since we don’t want to create a constructor function, where we manipulate the value of this
, defining an arrow function is a good choice.
It is shorter than writing:
const add = function (a, b) {
return a + b;
};
We can use the template literal location to define strings that can have expressions interpolated inside.
For instance, we write:
const numBottles = 100;
const str = `There are ${numBottles} bottles of beer on the wall.`;
console.log(str);
to interpolate the value of the numBottles
variable in the string.
As a result, str
is "There are 100 bottles of beer on the wall."
This is shorter than:
const numBottles = 100
const str = 'There are ' + numBottles + ' bottles of beer on the wall.`
which uses concatenation to put the value of numBottles
into the string.
The template literal notation is better if we want to concatenate any strings and expressions together.
And it also preserves any spaces and newline characters that we add to the string, which is something that regular strings don’t have.
The destructuring assignment syntax is a handy shorthand introduced with ES2015.
It lets us assign object properties and array entries as the values of variables in one line.
For example, we write:
const arr = [1, 2, 3, 4, 5];
const [a, b, c] = arr;
console.log(a, b, c);
to assign the first three entries of arr
to variables a
, b
and c
respectively with the destructuring.
Therefore a
is 1, b
is 2 and c
is 3.
This is much shorter than:
const arr = [1, 2, 3, 4, 5];
const a = arr[0];
const b = arr[1];
const c = arr[2];
console.log(a, b, c);
Since we have to use the index to get the value of the entries we want and then assign them to variables individually.
The destructuring syntax once again eliminates lots of repetition when we assign multiple array entries to as values of different variables.
The destructuring assignment syntax also works with object properties.
To use it with objects, we write:
const obj = {
x: 1,
y: 2,
z: 3,
};
const { x, y, z } = obj;
console.log(x, y, z);
to get the values of the x
, y
and z
properties in obj
and assign them to the variables x
,
y
and z
respectively.
As a result, x
is 1, y
is 2 and z
is 3.
This is much shorter than:
const obj = {
x: 1,
y: 2,
z: 3,
};
const x = obj.x;
const y = obj.y;
const z = obj.z;
which gets the value of each property and assigns them to variables in their own lines.
The destructuring syntax once again eliminates lots of repetition.
The spread operator lets us copy array entries and object values.
For instance, we write:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2];
console.log(arr3);
Then arr3
is [1, 2, 3, 4, 5, 6]
since we copied the entries of arr1
and arr2
into the new array with the spread operator
and assigned that as the value of arr3
.
This is equivalent to:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = arr1.concat(arr2);
console.log(arr3);
which also returned the merged version of arr1
and arr2
with arr1.concat
.
To use the spread operator with objects, we write:
const obj1 = {
a: 1,
b: 2,
c: 3,
};
const obj2 = {
b: 4,
c: 5,
d: 6,
};
const obj3 = {
...obj1,
...obj2,
};
console.log(obj3);
to merge the properties of obj1
and obj2
into the same object and assign the merged object to obj3
.
As a result, obj3
is:
{
a: 1,
b: 4,
c: 5,
d: 6
}
since properties b
and c
from obj2
override the values of the same properties in obj1
in the merged object because they’re
merged in later.
d
doesn’t exist in obj1
so it’s just copied over.
This is shorter than:
const obj1 = {
a: 1,
b: 2,
c: 3,
};
const obj2 = {
b: 4,
c: 5,
d: 6,
};
const obj3 = Object.assign({}, obj1, obj2);
which does the same thing but requires calling the Object.assign
method, which is longer than the ...
spread operator.
The spread operator also works with other iterable objects to spread iterable object entries into arrays.
We can use it by writing:
const arr = [...new Set([1, 2, 3])];
which copies the entries from the set iterable object into an array and assigns it to arr
.
The spread operator for iterable objects has been available since ES2015 and the object spread operator since ES2018.
JavaScript is a popular programming language for developing web applications and more.
Many new JavaScript features since 2015 which helps us write JavaScript programs in a shorter and readable fashion. The ternary operator was even available before 2015.
These handy shorthands make our code cleaner and easier to read.
John Au-Yeung is a frontend developer with 6+ years of experience. He is an avid blogger (visit his site at https://thewebdev.info/) and the author of Vue.js 3 By Example.