10 Important ES6 Features In JavaScript That Makes Your Life Easy

Md. Mostafa Al Mahmud
11 min readNov 3, 2020

--

JS ES6 Features mdmostafa.com

According to Wikipedia, JavaScript often abbreviated as JS is a programming language that conforms to the ECMAScript specification. JavaScript is high-level, often just-in-time compiled, and multi-paradigm. It has curly-bracket syntax, dynamic typing, prototype-based object-orientation, and first-class functions.

After ECMAScript 6 (ES6), JavaScript itself has been a massive changed in the history of the language. In this article, I will show you the interesting things that actually JavaScript makes our life easier than before.

So let’s get started!

Here’s the list of 10 features that, I think, I need to discuss on this blog that might help you understand.

  1. Hoisting Variables
  2. Block-Binding: Let and Const
  3. Default Parameters
  4. Rest and Spread Parameters
  5. Arrow Functions
  6. Destructuring Assignment
  7. Promises
  8. Classes
  9. Enhanced Object Literals
  10. Template Literals
  1. Hoisting Variables

Hoisting is a JavaScript default behavioral mechanism in which variableand functiondeclarations are moved to the top of the current scope before code executing.

We can see in the JavaScript lifecycle of variables processing that there are three parts such as the declaration, initialization or assignment, and usage like the following picture.

JavaScript Hoisting

We can not use or initialize any variablebefore the declaration and also it has to be maintained at the scope level.

var a = 5;function hoisting() {
a = 1;
var b = 2;
}

hoisting();

console.log(a);
/*
This is valid and considerable as a global variable outside hoisting() function
Result is 1
*/
console.log(b); // Error
/*
This is not accessible as a global variable because it is declared inside hoisting() scope
*/

Let’s see another example of a functiondeclaration.

// function declaration
function student(name, id) {
return `Name is ${name} and id is ${id}`;
}
let result = student('Mostafa', 101);console.log(result);
// Name is Mostafa and id is 101

It is a regular function that works well. It also will work well if I declare the functionafter calling the functionbecause of its declaration itself, not expression. Let’s see.

let result = student('Mostafa', 101);console.log(result);
// Name is Mostafa and id is 101
// function declaration
function student(name, id) {
return `Name is ${name} and id is ${id}`;
}

But now if I assign a function to a variable, it is considered as a function expressionand it is not to use before the initialization

let result = student('Mostafa', 101);console.log(result);
// Name is Mostafa and id is 101
// function expression
const student = (name, id) => {
return `Name is ${name} and id is ${id}`;
}
// Uncaught ReferenceError: Cannot access 'student' before initialization

Here the student is aconst variable but it is used before initialization. So it returns areference error .

But now if I initialize students at first then use it, it can be accessible. Let’s see!

// function expression
const student = (name, id) => {
return `Name is ${name} and id is ${id}`;
}
let result = student('Mostafa', 101);console.log(result);
// Name is Mostafa and id is 101

2. Block-Binding: Var, Let, and Const

Variable declarations havingvar are considered as if they are at the top of the function or it is treated as a global scope if it is declared outside of a function.

var vs let vs const

For making a clear idea about that, consider the following function definition:

function getName(name) {

if (name) {
var result = `Hello ${name}`;

return result;
} else {

// result exists here with a value of undefined

return null;
}

// result exists here with a value of undefined
}

Here we can see that varis declared in if block scope that is not a global scope but in JavaScript engine, behind the scene the getName function itself has been changed to like this;

function getName(name) {

var result;

if (name) {
result= `Hello ${name}`;

return result;
} else {

return null;
}
}

That is why we can access it in elseblock scope as well as getName function scope. But it is not a global variable that is accessible globally.

Now if we use let instead of var, the situation is changed dramatically. Let’s see an example,

function getName(name) {

if (name) {
let result = `Hello ${name}`;

return result;
} else {

// result does not exist here

return null;
}
// result does not exist here
}

It is because of ES6 let behavior as JavaScript engine does not permit let to be hoisted at the top level of the current block scope. Another difference var andletis that let can not be redeclared like var

For example,

var num = 1;let num = 2;
// Throw an error
if (condition) {

let num = 3;

// Does not throw any error
}

Here first let is not accessible because of num redeclaration but second let is valid because it is inif block scope.

3. Default Parameter

A default parameter means when a named parameter is passed by no value or undefined, it allows the named parameters to be initialized with default values at the time of function declaration.

function modulus(a, b) {

return a % b;
}

modulus(5, 2); // 1
modulus(5); // NaN

The second result is NaN because all the argument's requirements are not fulfilled.

But when we assign a value to b by condition, it works well.

function modulus(a, b) {  b = (typeof b !== 'undefined') ?  b : 2  return a % b;
}

modulus(5, 2); // 1
modulus(5); // 1

Basically, the default parameter helps us to handle NaN value in this instance when a user does not fulfill all the input fields.

Let’s see a real example of that!

function modulus(a, b = 2) {    return a % b;
}

modulus(5, 2); // 1
modulus(5); // 5

I think it is now more clear about that.

4. Rest and Spread Parameters

The most surprisingly topic to me the rest and spread because these look exactly the same each other but meaning is totally different. The syntax is that (...) and its presentation relies only on where it is used, how it is used. It's more confusing sometimes to developers when it is seen in the code snippet.

JavaScript three-dot rest vs spread

I will try my level best to show you the usages in different situations easily.

Spread Operator is unpacking the collected elements such as arrays into single elements. But Rest Operator is collecting all remaining elements into an array or object.

For example,

const arrOne = [‘I’, ‘love’, ‘Programming’]const arrTwo = [‘Programming’, ‘is’, ‘life’] const arr3 = [arrOne, arrTwo];console.log(arr3);
// [ [ ‘I’, ‘love’, ‘Programming’ ], [‘Programming’, ‘is’, ‘life’]]

It’s normal usage of array concatenation. Now I am using Spread (...) on the array to unpack the array look-a-like [[,,],[,,]] => [,,,,]

const arrThree = [...arrOne, 'and', ...arrTwo]console.log(arrThree);
// [ 'I', 'love', 'Programming', 'Programming', 'is', 'life']

Now I use rest (...) on the array [ ]

// Destructuring arrOne
const [idx1, ...restArrValue] = arrOne;
console.log(idx1, restArrValue);
// I [ 'love', 'Programming' ]

Again spread for unpacking the array

console.log(idx1, ...restArrValue);
// I love Programming

Now I will show you the rest and spread usages in an object meaning the same as before.

Let’s create an object as usual.

const person = {    
name: 'Mostafa',
age: 30,
gender: 'male',
status: 'developer'
}

Now I assign a new property to the object and use a spread operator for unpacking the object person

const updatePerson = {    // spread for unpacking the object { { }, { }} ===> { }         
...person,
degree: 'MSC'
}console.log(updatePerson);
/*
{
name: 'Mostafa',
age: 30,
gender: 'male',
status: 'developer',
degree: 'MSC'
}
*/

Again using rest operator to the updated object updatePerson

const {    
name,
...restObjValue
} = updatePerson;
console.log(name, restObjValue);
// Mostafa { age: 30, gender: 'male', status: 'developer' }

I hope, it makes sense to you the usages of rest and spread operator in JavaScript ES6.

5. Arrow Functions

An arrow function expression is a compact alternative to a traditional function expression, but is limited and can’t be used in all situations according to MDN.

Javascript ES6 Arrow function

An arrow function is used in an only function expression

const add = (num1 = 0, num2 = 2) => { 
return num1 + num2;
}
console.log(add(undefined, 1)); // 1
console.log(add(1)); // 3

Return a single statement, no need for curly braces { }, and return keyword

const multiply = (num1 = 0, num2 = 2) => num1 * num2;console.log(multiply(undefined, 1)); // 0console.log(multiply(1)); // 2 const area = (length, width) => length * width;
console.log(area(5, 3)); // 15

When a single/only one parameter is used, there is no need to use bracket ()

const modulus = num1 => num1 % 3;console.log(modulus(1)); // 1
console.log(modulus(3)); // 0

When there is no parameter, use bracket ()

const selfItem = () => 1;
console.log(selfItem());

If you create a function in an object, there is no need to use arrow function. For example,

const bio = {    
name: 'Mostafa',
age: 29,
profession: 'Web Developer',
showBio: function () {
console.log(this);
/* Here this means the full object itself. Output is:
{
name: 'Mostafa',
age: 29,
profession: 'Web Developer',
showBio: [λ: showBio]
}
*/
return `This is ${this.name}
and I am ${this.age}.
I am a ${this.profession}.`
}
}
console.log(bio.showBio());
// This is Mostafa and I am 29. I am a Web Developer.

These all are the usages of arrow function in diffrenet angles as well.

6. Destructuring Assignment

The destructuring assignment syntax means that it is a JavaScript expression that unpack values from arrays, or properties from objects, into a different variables. In other words, destructuring is the pulling out of the values from an array or properties from an object. Thats it.

JavaScript ES6 destructuring method

Here I will show you the examples of both usages as array destructuring and object destructuring. So let’s get started!

Array destructuring examples:

const myBio = ['Mostafa', 29, 'Web Developer'];

You have to maintain the chronological order in the array like;

const [name] = myBio;
const [, age] = myBio;
const [, , profession] = myBio;
console.log(name); // Mostafa
console.log(age); // 29
console.log(profession); // Web Developer

Also, you can destructre all the variables in the array and use them

const [name, age, profession] = myBio;

So index-variable order maintain must be followed in array destructuring.

Destructuring with rest operator that I have discussed above is like that

const friendsArray = ['a', 'b', 'c', 'd', 'e']
const [bestFriend, ...averageFriends] = friendsArray;
console.log(bestFriend); // a
console.log(averageFriends); // [ 'b', 'c', 'd', 'e' ]

Object destructuring examples:

const objBio = {    
userName: 'Mostafa',
id: 001,
status: 'Developer',
shareBio: {
facebook: true,
twitter: true,
}
}
const { userName, id, status, isMarried} = objBio;console.log(userName, id, status, isMarried);
// Mostafa 1 Developer true

You can use nested destructuring as like below;

const { shareBio: { facebook, twitter } }= objBio;console.log(facebook, twitter); 
// true true

Also, note that you do not have to use in chronological order like array destructuring.

Hope, it make sence to you!

7. Promises

One of the most powerful features of JavaScript is how it handles itself asynchronous programming in this easiest way. As JavaScript initiated as a language basically for the web, it had to be able to respond to user interactions asynchronously such as clicks, hovers, key presses and so on.

JavaScript ES6 Promises

Let’s see a rather trivial example of a delayed example of asynchronous execution with setTimeout()

const processData = () => {    
setTimeout(() => {
console.log(1); // after 1 second
setTimeout(() => {
console.log(2); // after 2 second
setTimeout(() => {
console.log(3); // after 3 second
}, 1000);
}, 1000);
}, 1000);
}
processData();

To handle this bad practice, Promise is used

const promiseData = new Promise((resolve, reject) => {  
setTimeout(() => {
resolve(1);
reject(Error('Error...'));
}, 1000);
});
console.log(promiseData);
promiseData.then(data => {
console.log(data);
})
.catch(error => console.log(error));

8. Classes

JavaScript classes that is introduced in ECMAScript 2015 (ES5) are generally called syntactical sugar over JavaScript ‘s existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.

When class is instantiated with ‘new’ keyword, constructor is running automatically.

class Student {
constructor(id, name, age) {
this.id = id;
this.name = name;
this.age = age;
this.lang = [];
this.country = 'Bangladesh';
}
getInfo() {
return `
id - ${this.id}
name - ${this.name}
age - ${this.age}
language -${this.lang.join(', ')}`;
}

Now you can instantiate any object using this class constructor

const student1 = new Student(1, 'Mostafa', 29);
console.log(typeof (student1)); // object
const student2 = new Student(2, 'Mahmud', 30);console.log(student1);
/*
Student {
id: 1,
name: 'Mostafa',
age: 29,
country: 'Bangladesh'
}
*/
console.log(student1.name); // Mostafa

When you need full data, just call getInfo()

console.log(student1.getInfo());

That’s the basic idea of class constructor in ES6 as well.

9. Enhanced Object Literals

A JavaScript object literal is a comma-separated list of name-value pairs wrapped in curly braces. Object literals encapsulate data, enclosing it in a tidy package. This minimizes the use of global variables which can cause problems when combining code.

If property and value is the same name, no need to use repeatedly

function bio({
firstName,
lastName,
coveredField
}) {
return {
firstName,
lastName,
commonLang: ['html', 'css', 'js', 'c', 'c++'];
coveredField() {
return `My first name is ${this.firstName},
second name is ${this.lastName}
and I covered ${coveredField}
`;
}
}
}
const myBio = bio({
firstName: 'Mostafa',
lastName: 'Mahmud',
coveredField: 'ES6'
});
console.log(myBio.firstName); // Mostafa
console.log(myBio.commonLang); // ['html', 'css', 'js', 'c', 'c++']
console.log(myBio.coveredField());
// My first name is Mostafa, second name is Mahmud and I covered ES6

10. Template Literals

According to MDN, “Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them.”

Template literals javascript

Here is an example of practical usage:

const firstName = 'Mostafa';
const profession = 'developer';
const workField = 'wep application'
function modify(strings, ...restValues) { console.log(arguments);
// all data (static and dynamic) in [[array], array]
console.log(strings, restValues);
// divided array in output [static data array], [dynamic data array]

let str = '';
strings.forEach((string, i) => { str += `${string} <b> ${restValues[i] || ''}</b>`; }); return str;}

ES6 Tagged Template Literals to modify dynamic data in the template string. Tag functions modify() don’t even need to return a string always!

const html = modify `        <h1> This is ${firstName.toUpperCase()}</h1>        <p> I am a ${profession}</p>        <p> I am working on ${workField}</p>        `document.body.innerHTML = html;

That's all about ES6 important features that developers face and explore in their JavaScript programming life.

If this article is helpful for you, please do not clap for this.

Enjoy your coding!

--

--

Md. Mostafa Al Mahmud

Full-Stack Software Engineer || JavaScript Lover || Experienced with MERN Stack || Mongo, Express, React, Node, ES6, Netlify, Heroku, Firebase, Version Control