5 JavaScript Features That You Might Not Know About
Learn 5 extremely useful JavaScript features to use in your next line of code
JavaScript is a hefty programming language with a vast amount of features that makes it possible to implement complex features in applications to make the world a better place — well, that’s how I see it.
Moving on to the goods, let’s not let this linger any longer. We will be discussing these 5 JavaScript features:
1. Optional Chaining
2. Nullish Coalescing
3. Styling Console Log
4. Defer/Async Loading
5. Object Shorthand
Optional Chaining
What is optional chaining? It’s an operator that was introduced as a new feature in ES2020 and it permits you to access the value of a property that’s located deep inside a chain of objects without the extra work of checking if each reference in the chain is null
or undefined
.
Let’s say one of the references in this chain of objects is null
or undefined
, the optional chaining operator will short circuit and return undefined
.
It looks like this: ?.
Cool, right? But how does it look in action? We will get there soon, let’s break this down first.
In this example we are going to use a special function.
class Sandwich {
constructor(bread, toppings){
this.bread = bread
this.toppings = toppings
}; printOrder(){
console.log(this);
}:
};
let printVeggieToppings = (sandwich) => {
console.log(sandwich.toppings.veggie);
};
const yourSandwich = new Sandwich(
'Multigrain',
{
meat: 'Tofu',
cheese: 'Vegan Swiss',
veggie: 'Cucumbers'
},
);yourSandwich.printOrder();
printVeggieToppings(marioSandwich);
We declared a class called Sandwich
, created a yummy object , and we’ll pass delicious arguments to our constructor parameters — because food is always the answer.
Inside of our class we also declared a static method printOrder
that will log our object in the console. Moving on, we declared a function printVeggieToppings
that will log the veggie topping of our delicious sandwich.
Right after, we’ll declare yourSandwich
variable and set its value to a new instance of our Sandwich
object, and finally invoke printOrder
and printVeggieToppings
.
What should we see in our console?
Sandwich {
bread: 'Multigrain',
toppings: {
meat: 'Tofu',
cheese: 'Vegan Swiss',
veggie:'Cucumbers'
}
}Cucumbers
The invocation of printOrder
logs our Sandwich
object and printVeggieToppings
logs the value of the property veggie
.
Perfect.
What would we see in the console if we pass undefined
as an argument to our toppings
parameter?
TypeError: Cannot read property 'veggie' of undefined
Why? Because JavaScript is trying to access toppings.veggie
while toppings is undefined
, so it throws an error. This is an error in JavaScript that you can run into frequently and here are two ways you would usually go about it pre-optional chaining operator.
let printVeggieToppings = (sandwich) => {
console.log(
sandwich && sandwich.toppings && sandwich.toppings.veggie
);
};
OR
let printVeggieToppings = (sandwich) => {
if(sandwich && sandwich.toppings){
console.log(sandwich.toppings.veggie)
}
};
Both options will result in undefined
and will not throw an error. In the first solution it will short circuit once it reaches sandwich.toppings
and in the second solution it will never enter the scope block because the condition is not met.
Here comes the optional chaining operator ?.
. Instead of writing all that code, we can keep our original code block and simply add a ?
to it like this:
let printVeggieToppings = (sandwich) => {
console.log(sandwich?.toppings?.veggie);
};
Clean right? What’s happening here though?
Let’s recap.
JavaScript is checking if sandwich
is a null
or undefined
value, if not, it will keep going down the chain of objects and keep checking. However, if there’s a null
or undefined
value anywhere in that chain of objects it will short circuit and log undefined
in our console and not throw an error.
Otherwise, it will log the property’s value, in our case that’s Cucumbers
. Also, it would be good to mention that this would work with functions as well.
Here is an example using our printOrder
function.
class Sandwich {
constructor(bread, toppings){
this.bread = bread
this.toppings = toppings
};printOrder(){
console.log(this);
}:
};const yourSandwich = new Sandwich(
'Multigrain',
{
meat: 'Tofu',
cheese: 'Vegan Swiss',
veggie: 'Cucumbers'
},
);yourSandwich.printOrder?.();
At the very bottom you’ll see yourSandwich.printOrder?.()
— that looks weird, I know.
JavaScript in this example is not only checking if printOrder
exists, it’s also checking if it’s a function! If it does exist and it’s actually a function, then it will successfully execute and log our Sandwich
object to the console. If it does not exist or it’s not a function, we find a nice undefined
waiting for us in the console.
Nullish Coalescing
If you thought optional chaining operator was cool, you’re going to love nullish coalescing operator. What is it?
MDN Web Docs said it best — “a logical operator that returns its right-hand side operand when its left-hand side operand is
null
orundefined
, and otherwise returns its left-hand side operand”.
It looks like this: ??
Let’s jump right into an example.
let favNumber = (num) => {
num = num || 'No number for you';
console.log(`Your favorite number is: ${num}`);
}favNumber(9);
What would we see in our console when favNumber
is invoked?
Your favorite number is: 9
Now, what if someone’s favorite number happened to be 0 and we invoke favNumber(0)
like this?
Your favorite number is: No number for you
The OR operator returns the right-hand side operand if the left-hand side operand is any falsy value, not just null
or undefined
. Let’s swap the OR operator with the nullish coalescing operator.
let favNumber = (num) => {
num = num ?? 'No number for you';
console.log(`Your favorite number is: ${num}`);
}favNumber(0);
The nullish coalescing operator returns the left side operand if the right-hand side operand is null
or undefined
value and that’s why we’d see this in our console.
Your favorite number is: 0
Styling Console Log
The next time you’re using the console — splash some styling! In the example below we used two CSS styles, font-size
and color
, each were passed as an argument to the console.log()
. For each CSS style that gets passed as an argument you’ll need to add %c
before the text you’d like to style.
Defer/Async Loading
Let’s say we have a test.html
file and we link an external JavaScript file to it called index.js
using a script
tag. The index.js
file looks a little something like this:
//index.jsconst title = document.querySelector("h1");title.style.color = "blue";
Usually you’ll find the link to an external JavaScript file nested under the body
tag of the HTML file, like this:
//test.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>This needs to load NOW!</h1>
<script src="index.js"></script>
</body>
</html>
The thing with having the script
tag right above the closing body
tag is that the download of your script
tag doesn’t start until the browser gets to it, and since it’s the last thing to download in test.html
, the browser will read it last and that could slow down your download speed.
Instead, you can place your script
tag like this:
//test.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="index.js" defer></script></head>
<body>
<h1>This needs to load NOW!</h1>
</body>
</html>
Take a closer look, not only did we change the script
tag’s placement, we added the defer
attribute right after the src
attribute — and that makes all the difference. By using the defer
attribute it tells the browser not to wait for the script and to continue to process the HTML, and build the DOM. Under the hood the script loads “in the background”, and then runs when the DOM is fully built.
It’s good to keep in mind these two key characteristics of the defer
attribute:
- Scripts with
defer
always execute when the DOM is ready (but beforeDOMContentLoaded
event). - Scripts with
defer
never block the page.
Object Shorthand
Object shorthand was introduced with ES6 and it’s quite clean looking when implemented. Lets say we have two variables:
const choiceOfCar = 'Jeep';
const makeOfCar = 'Wrangler';
We want to use these variables in an object called car
as key-value pairs. If we were to use the ES5 syntax, our object would like this:
const choiceOfCar = 'Jeep';
const makeOfCar = 'Wrangler';const car = {
choiceOfCar: choiceOfCar,
makeOfCar: makeOfCar,
};
However, with ES6 syntax our car
object would look like this:
const choiceOfCar = 'Jeep';
const makeOfCar = 'Wrangler';const car = {
choiceOfCar,
makeOfCar,
};console.log(car);
The object shorthand converts the variable name to a key and will set the key’s value as the variable’s value. If we would log the car
object to our console, this is what we’d see:
{ choiceOfCar: 'Jeep', makeOfCar: 'Wrangler' }
Thank you for reading! Hope you found this useful, share if you did.
Connect with me on LinkedIn or Instagram: @marioeldin
Have a great day/night!
— Mario Eldin