Enhance Your JavaScript Skills with ES6 Features
The ES6 syntax is arguably one of the most significant updates ever made in the evolution of the JavaScript ecosystem. It offers a series of modifications that simplify everyday programming operations and enhance your web development experience.
Whether you're an experienced programmer seeking to refresh your knowledge of the syntax, or a beginner–entirely new to the syntax, this document comprehensively describes all you need to get started using the ES6 syntax.
Introduction
ECMAScript version 6 (ES6)—also referred to as ECMAScript 2015—is a version of JavaScript which was released in 2015 as a major update to the JavaScript programming language.
Older JavaScript versions have had several challenges and limitations that made them less developer-friendly and harder to maintain for complex applications. However, the introduction of ES6 syntax to the JavaScript ecosystem has proven to be a game changer as it addresses the limitations experienced in the older versions of the language.
Knowledge of the ES6 syntax will enhance your ability to write codes that are clean, concise, easy to read, and maintain.
Discussed below are key ES6 modifications that will improve your JavaScript code:
The
var
,let
andconst
keywordsThe current use of the
let
andconst
keywords provide solutions to the challenges of variable management associated with the fomerly usedvar
keyword.
The solutions provided are:Block-scoped variables
Before ES6,
var
declared variables only existed in either global or function scope.Global Scope:
var name = 'Susan'; console.log(name);// This outputs Susan
Function Scope:
function Greet(){ var name = 'susan'; console.log ('Hello ' + name)// This outputs Hello Susan }
The
let
andconst
variables introduced in ES6 now provide something called a Block Scope.
You create a Block scope by enclosing your code within curly braces{}
. This ensures that variables can only be accessed within the code block where you declare them.For example
Using
let
:let name = 'Jamie';// Here name is Jamie if (true){ let name = 'Susan'; console.log(name);// This outputs Susan } console.log(name);// This outputs Jamie
Using
const
:const name = 'Jamie';// Here name is Jamie if (true){ const name = 'Susan'; console.log(name);// This outputs Susan } console.log(name);// This outputs Jamie
Using
var
:var name = 'Jamie';// Here name is Jamie if (true){ var name = 'Susan'; console.log(name);// This outputs Susan } console.log(name);// This outputs Susan
Block scope prevents unintended access to variables thereby helping to reduce scope related bugs.
Variables declared usingvar
do not have block scope therefore redeclaring avar
variable within a block scope also redeclares and reassigns the variable globally.Variable redeclaration and reassignment
In contrast to the
var
keyword, variables declared withlet
andconst
cannot be redeclared within the same scope where you have previously declared them. Any attempt to redeclarelet
andconst
variables within the same scope returns aSyntaxError
.
Usinglet
andconst
for variable declaration reduces the risk of variable conflict commonly associated with thevar
keyword.Using
let
:let name = 'Jamie'; let name = 'May'; console.log(name);// outputs a "SyntaxError: Identifier 'name' has already been declared" if (true){ let name = 'Susan'; let name = 'Shades'; console.log(name);// outputs a "SyntaxError: Identifier 'name' has already been declared" }
Using
const
:const name = 'Jamie'; const name = 'May'; console.log(name);// outputs a "SyntaxError: Identifier 'name' has already been declared" if (true){ const name = 'Shades'; const name = 'Susan'; console.log(name);// outputs a "SyntaxError: Identifier 'name' has already been declared" }
Using
var
:var name = 'Jamie'; var name = 'May'; console.log(name);// outputs May if (true){ var name = 'Shades'; var name = 'Susan'; console.log(name);// outputs Susan }
It is however worthy to note that while you can reassign a
let
variable, you cannot reassign aconst
variable. Variables declared usingconst
are immutable and therefore their values remain constant.
The "TypeError: Assignment to constant variable
" is raised when you attempt to reassign aconst
variable.Using
let
:let name = 'Jamie'; name = 'May'; console.log(name);// outputs May if (true){ let name = 'Susan'; name = 'Shades'; console.log(name);// outputs Shades }
Using
const
:const name = 'Jamie'; name = 'May'; console.log(name);// outputs a "TypeError: Assignment to constant variable" if (true){ const name = 'Shades'; name = 'Susan'; console.log(name);// outputs a "TypeError: Assignment to constant variable" }
The use of
let
andconst
makes your code easy to understand and maintain as readers can easily identify variables that may change from those that will remain constant. This is seen as good practice and helps for easy collaboration with other developers.
Template literals
Concatenation is the process of combining two or more strings to form a new string.
Before ES6 was introduced, JavaScript developers concatenated strings and variables by using the addition operator (+
). This often resulted in a messy and sometimes complicated code base.
ES6 introduced template literals as a much simpler way to concatenate strings and variables.The introduction of template literals addressed pain-points in the following areas:
String concatenation
Before ES6, developers built complex strings by doing this;
var name = 'John'; // this is a regular string var surname = 'Doe'; let greeting = 'Hello ' + name + surname + ' , nice to meet you.' console.log(greeting); // output = Hello John Doe, nice to meet you.
This method of concatenation turns out to be not only tedious, but also produces codes that are hard to read and prone to errors. But with the introduction of template literals in ES6, you can now easily concatenate strings and/or variables by simply enclosing them within backticks.
However, when substituting embedded expressions such as variables within the template string, enclose them within a dollar symbol and curly braces
${}
. This substitution technique is called string interpolation.For example
let name = `John`; // this is a template string let surname = `Doe`; let greeting = `Hello ${name} ${surname}, nice to meet you.` console.log(greeting); // output = Hello John Doe, nice to meet you.
Multiline strings
Using template literals in ES6 allows you to also create multiline characters with ease and without the complexity of the newline character (
\n
) previously used in earlier JavaScript versions. In ES6, you can easily add new lines to your code just by hitting the enter key.ES5:
var output = 'This is \n a newline \n character'
ES6:
const text = ` This is a newline character`
Destructuring
Destructuring in JavaScript is simply the unpacking or extraction of the values of an object or array into individual variables.
Object destructuring
Consider the object:
const object = { name: 'Douglas', age: 20, isMale: true }
Before ES6, there were two prevalent methods of accessing object property values and assigning variable names to them.
This:
const name = object.name; const age = object.age; const isMale = object.isMale; console.log(name);// outputs Douglas console.log(age);// outputs 20 console.log(isMale);// outputs true
And this:
const name = object['name']; const age = object['age']; const isMale = object['isMale']; console.log(name);// outputs Douglas console.log(age);// outputs 20 console.log(isMale);// outputs true
But with the introduction of the destructuring syntax in ES6, you can now access object property values and assign variable names to them in a much simpler way by doing this:
const {name, age, isMale} = object; console.log(name);// outputs Douglas console.log(age);// outputs 20 console.log(isMale);// outputs true
The syntax above destructures the object using the existing object properties as variable names. However, if you wish to assign a custom variable name to an object property value, separate the object property from your preferred custom variable using a colon (
:
).For example
const {name:customName, age:customAge} = object; console.log(customName);// outputs Douglas console.log(customAge);// outputs 20
The colon (
:
) reassigns the values of thename
andage
property to thecustomName
andcustomAge
variables respectively.Array destructuring
Consider the array:
const array = ["Douglas", 20, true]
Before ES6, developers accessed array elements and assigned variable names to them using their index value like this:
const name = array[0]; const age = array[1]; const isMale = array[2]; console.log(name);// outputs Douglas console.log(age);// outputs 20 console.log(isMale);// outputs true
But with the ES6 destructuring syntax, you can now directly access array elements and assign your preferred variable names to them in a much simpler way by doing this:
const [name,age,isMale] = array console.log(name);// outputs Douglas console.log(age);// outputs 20 console.log(isMale);// outputs true
If the array contains more elements than the variable names assigned, the rest of the unassigned array elements are discarded. However, if the array contains less elements than the declared variables, the unassigned variables are returned
undefined
.For example
const [name,age,isMale,occupation] = array console.log(name);// outputs Douglas console.log(age);// outputs 20 console.log(isMale);// outputs true console.log(occupation);// outputs undefined
If you do not intend to use an element within the array, you may skip the position of the element using a comma.
const [name,,isMale] = array console.log(name);// outputs Douglas console.log(isMale);// outputs true
Arrow function
Arrow function is another significant improvement of ES6 over previous JavaScript versions. It earns its name from the striking resemblance of its basic syntax to an arrow head (
=>
). The arrow function feature provides a shorter and simpler way of writing function expressions compared to traditional functions.Before ES6, JavaScript developers wrote traditional functions using the
function
syntax like this:function functionName(parameter){ return expression; }
Using the ES6 arrow function syntax, you can now create functions like this:
let functionName = (parameter) => {return expression}
The function expression below returns the sum of two numbers:
Using regular function:
function add(parameter1, parameter2){ return parameter1 + parameter2; } add(7,3)// outputs 10
Using arrow function:
let add = (parameter1, parameter2) => { return parameter1 + parameter2; } add(7,3)// outputs 10
If the return expression doesn't span multiple lines, you can skip the
return
keyword and curly braces{}
like this:let add = (parameter1, parameter2) => parameter1 + parameter2;
If the function expression takes a single parameter, you can further simplify your code by omitting the parentheses as follows:
let functionName = parameter => expression;
The function below returns the cube value of its argument:
let cubeVal = x => x**3; cubeVal(3)// outputs 27
In the example above, note that the function stills runs perfectly without the parentheses
()
, curly braces{}
, andreturn
keyword.Default function parameters
With ES6 JavaScript, it is now possible to set default values for function parameters during function declaration. If you do not provide any arguments when calling the function, these default values will be used, ensuring that the function still runs as it should.
Example 1
The function
BMI()
below calculates the body mass index (BMI) of an individual:const BMI = (weight = 70, height = 1.73) => { return `your BMI is ${(weight / ((height**2).toFixed(2))).toFixed(2)}`}
Note how the
BMI()
function above implements the ES6 arrow function, template literal, and default function parameter. The default values assigned to the weight and height parameters ensure that the function still returns a valid value if you do not explicitly pass an argument when calling the function.BMI()// your BMI is 23.41
BMI(110,1.95)// your BMI is 28.95
Example 2
const identity = (name='Guest') =>{ alert(`Hello ${name}`) }
Running the
identity()
function above alerts the name of a hypothetical user accessing an online service through a guest account. The default parameter ensures that the code does not break even when a user isn't signed into their account.Identity()// Hello Guest
A signed in user will get a custom 'Hello' message addressed to their user.
Identity('Greek')// Hello Greek
Classes
Classes are templates or blueprints for creating multiple instances of objects with similar properties. By using classes, you can create new objects that share common features without duplicating the code. Each instance of the class will have its own specific property values but still share the same methods and behaviour defined in the class.
How to create a class
Follow the syntactic steps outlined below to create a class:
- Define the class by using the
class
keyword followed by the class name and curly braces{}
- Within the class, declare a
constructor()
method to initialize properties that will be shared by all instances of the class. - Add methods to the class for defining the behaviour and functionality of other object instances to be created from the class.
(Optional) Use the
extends
keyword to create a subclass that inherits properties and methods from a parent class.Example 1
The expression below creates a simple
Vehicle
class that containsbrandName
,model
, andyearOfProd
properties.class Vehicle { constructor(brandName,model,yearOfProd) { this.brandName = brandName; this.model = model; this.yearOfProd = yearOfProd; } description(){ return `This car is a ${this.brandName} ${this.model} produced in ${this.yearOfProd}`; } age(){ let date = new Date(); return `This ${this.brandName} was produced ${date.getFullYear()-this.yearOfProd} year(s) ago`; } }
From the
Vehicle
class created above, you can now generate new object instances with unique property values by using thenew
keyword like this:let firstCar = new Vehicle('Tesla', 'Plaid', 2021)
The code structure above automatically generates a
firstCar
object that looks like this:let firstCar = { brandName: "Tesla" model: "Plaid" yearOfProd: 2021 }
The
firstCar
object also has access to all the properties and methods in theVehicle
class.console.log(firstCar.brandName)// Tesla console.log(firstCar.model)// Plaid console.log(firstCar.yearOfProd)// 2021 console.log(firstCar.description())// This car is a Tesla Plaid produced in 2021 console.log(firstCar.age())// This Tesla was produced 2 year(s) ago
You can also extend the properties and methods of a predefined (parent) class to a new class (subclass) using the
extends
keyword andsuper()
method. Thesuper()
method of the subclass calls theconstructor()
method of the parent class to obtain access to the properties and methods defined within it.Example 2
The expression below creates a
SuperBikes
class that extends thebrandName
,model
, andyearOfProd
properties of theVehicle
class, but also contains a newhorsePower
property of its own.class SuperBikes extends Vehicle { constructor(brandName, model, yearOfProd, horsePower) { super(brandName, model, yearOfProd); this.horsePower = horsePower; } bikeDesciption(){ return `This is a ${this.brandName} ${this.model}. It was produced in ${this.yearOfProd} and has ${this.horsePower} horsePower.` } }
You can now generate as many object instances of the
SuperBike
class as required.Example 3
let firstBike = new SuperBikes('Suzuki', 'Hayabusa', 2012, 297)
New objects will have access to the properties and methods of the
SuperBike
class, and by extension, those of theVehicle
class. This means that you can now do something like this:console.log(firstBike.age())// This Suzuki was produced 11 year(s) ago console.log(firstBike.bikeDesciption())// This is a Suzuki Hayabusa. It was produced in 2012 and has 297 horsePower.
The template-like nature of JavaScript classes promotes code reusability, allowing you to easily write scalable and maintainable codes.
- Define the class by using the
For of
The
for..of
syntax is an ES6 looping construct used for performing iterations over a wide range of iterable data stuctures–this includes arrays, strings, NodeLists, and collections. It offers an intuitive way of handling loop operations without the complexities ofindex[i]
management associated with the traditionalfor
loop.syntax
for (variable of iterable){ statement to be executed.. }
To use the
for..of
syntax, initialize a variable with your preferred name using thelet
orconst
keyword. This variable is set to each value of the iterable object for every iteration and is subsequently utilized in the execution statement.Here are a few applications of the
for..of
syntax:Iterating over an array
Consider the following array:
let scores = [23,35,15,40]
The code below returns the sum of the total numbers in the
scores
array.let sum = 0 for(const score of scores){ sum+=score; } console.log("The total sum of the scores is: ", sum)//The total sum of the scores is: 113
In this example, the
for..of
loop iterates through each number of thescores
array. During each iteration, thescore
variable is set to the value of the current number in the array and then added to thesum
.
Finally, the code outputs the value of thesum
, which represents the addition of all the elements in the array.Iterating over a string
Consider the string:
const language = 'javascript'
The code below iterates through each character of the string
'javascript'
, and logs to the console, any vowel character.const vowels = 'aeiou'; for(const char of language){ if(vowels.includes(char)){ console.log(char);//aai } }
Iterating over a NodeList
Iterating over items within a NodeList allows for versatile DOM manipulation.
For example, consider a hypothetical NodeList containing all button elements in the DOM;let buttons = document.querySelectorAll('button');
Using the
for..of
loop, you can dynamically add an event listener to each button element in the NodeList without having to manually do so one after the other.for(const button of buttons){ button.addEventListener('click', () => { button.style.transform = 'translateY(1px)'; }); }
The event listener listens for a
click
event and adds a css transform property on all buttons, providing the user with an interactive experience in where they appear to be pushed in when clicked.Rest parameter
The rest parameter allows you to create functions capable of accepting a variable number of arguments as an array, without explicitly defining them during function declaration.
Only one rest parameter is allowed in a function definition, and it must be positioned as the final parameter within the function definition.syntax
To create a rest parameter, prefix the parameter with three dots (
...
);const myFunction = (param1, param2, ...myRest) => { statement to be executed.. }
Conventionally, you must declare an argument as a parameter during function declaration before calling the function. This means that any argument you pass into the function call without having defined it during function declaration, the function will not execute it.
For example
const add = (a,b) => { return `the sum of numbers is ${a+b}` }
add(5,7)//the sum of numbers is 12
add(5,7,8,12)//the sum of numbers is 12
However, with the rest parameter, you can create a function that executes any number of arguments passed into the function call;
Example 1
const add = (...rests) => { let sum = 0 for(const rest of rests){ sum+=rest }; return `the sum of numbers is ${sum}`; }
add(1,2,3,4,5)//the sum of numbers is 15
add(10,20,30,40,60,90)//the sum of numbers is 250
Rest parameters are array instances, therefore, you can execute instructions on them using array methods such asmap()
,filter()
,sort()
,reduce()
,forEach()
, and so on.Example 2: Using the
map
methodconst multiply = (...arguments) =>{ return arguments.map(arg=>arg*2) }
multiply(10,20,40,50)//outputs [20,40,80,100]
Example 3: Using the
forEach
methodconst multiply = (...arguments) =>{ return arguments.forEach(arg=>arg*2) }
multiply(10,20,40,50)//outputs [20,40,80,100]
Conclusion
ES6 has become the industry-standard syntax in the JavaScript ecosystem due to it's widespread adoption and ongoing support. Proper knowledge of the syntax empowers you to write codes that are clean, concise, easy to read, and maintain. As the JavaScript ecosystem continues to evolve, embracing ES6 and subsequent JavaScript versions are essential to staying relevant in the modern web development practice.
Subscribe to my newsletter
Read articles from Godspower Amanze directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Godspower Amanze
Godspower Amanze
Front-end developer (React) and technical writer with a passion for solving business problems by transforming them into reasonable logic with clear and concise documentation.