Sitemap
Press enter or click to view image in full size

JavaScript ES6 Features

--

What is ECMAScript 6 (or ES6)

ECMAScript 6 (ES6), also known as ECMAScript 2015, is a crucial milestone in the evolution of the JavaScript programming language. ES6 introduced concepts like template literals for flexible string interpolation, destructuring assignment made it easier to extract values from objects and arrays, while the ‘let’ and ‘const’ keywords provided block-scoped variable declarations, spread/rest operator, arrow functions for concise function expressions.

The let Keyword

ES6 introduces the new let keyword for declaring variables. Prior to ES6, the only way to declare a variable in JavaScript was the var keyword. Let's see what's the difference between them is.

There are two critical differences between the var and let. Variables declared with the var keyword are function-scoped or globally scoped (if declared outside of a function) and hoisted at the top within its scope, whereas variables declared with let keyword are block-scoped ({}) and they are not hoisted.

Block scoping simply means that a new scope is created between a pair of curly brackets i.e. {}.

// Variable declared with 'var' in ES5
var name = "John";

function sayHello() {
if (true) {
var name = "Alice";
console.log("Inside if block:", name); // Inside if block: Alice
}

console.log("Outside if block:", name); // Outside if block: Alice
}

sayHello();

console.log("Global scope:", name); // Global scope: John
// Variable declared with 'let' in ES6
let name = "John";

function sayHello() {
if (true) {
let name = "Alice";
console.log("Inside if block:", name); // Inside if block: Alice
}

console.log("Outside if block:", name); // Outside if block: John
}

sayHello();

console.log("Global scope:", name); // Global scope: John

The const Keyword

The const keyword is used to declare variables that cannot be reassigned after their initial assignment. It provides a way to create constants in JavaScript, making code more robust and self-explanatory. They are also block-scoped like let.

const PI = 3.14;
console.log(PI); // 3.14
PI = 10; // error

The for...of Loop

The for...of loop is a modern iteration construct introduced in ES6 (ECMAScript 2015) for easily looping through iterable objects such as arrays, strings, maps, sets, and more. It simplifies the process of iterating over elements compared to traditional for or for...in loops. Here's how to use it:

// Iterating over an array
const fruits = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
console.log(fruit);
}

// Iterating over a string
const sentence = "Hello, World!";
for (const char of sentence) {
console.log(char);
}

// Iterating over a Map
const myMap = new Map([
["key1", "value1"],
["key2", "value2"],
]);
for (const [key, value] of myMap) {
console.log(`${key}: ${value}`);
}

// Iterating over a Set
const mySet = new Set([1, 2, 3, 2, 1]);
for (const number of mySet) {
console.log(number);
}

The for...of loop is particularly useful when working with collections of data and is preferred over traditional for loops when you need to iterate over the elements themselves rather than their indices or keys.

It doesn’t work for iterating over the properties of a plain JavaScript object. For iterating over object properties, you can use other techniques such as for...in or Object.keys(), Object.values(), or Object.entries() methods.

Template Literals

Template literals provide an easy and clean way create multi-line strings and perform string interpolation. Now we can embed variables or expressions into a string at any spot without any hassle.

Template literals are created using back-tick (` `) character instead of the usual double or single quotes. Variables or expressions can be placed inside the string using the ${...} syntax. Compare the following examples and see how much useful it is:

// Simple multi-line string
let str = `The quick brown fox
jumps over the lazy dog.`;

// String with embedded variables and expression
let a = 10;
let b = 20;
let result = `The sum of ${a} and ${b} is ${a+b}.`;
console.log(result); // The sum of 10 and 20 is 30.

While in ES5, to achieve the same we had to write something like this:

// Multi-line string
var str = 'The quick brown fox\n\t'
+ 'jumps over the lazy dog.';

// Creating string using variables and expression
var a = 10;
var b = 20;
var result = 'The sum of ' + a + ' and ' + b + ' is ' + (a+b) + '.';
console.log(result); // The sum of 10 and 20 is 30.

Default Values for Function Parameters

In ES6 (ECMAScript 2015), you can set default values for function parameters, which allows you to specify a default value that will be used if an argument is not provided when calling the function. This feature makes it more convenient to handle optional parameters or provide fallback values. Here’s how to define default values for function parameters:

function sayHello(name='World') {
return `Hello ${name}!`;
}

console.log(sayHello()); // Hello World!
console.log(sayHello('John')); // Hello John!

While in ES5, to achieve the same we had to write something like this:

function sayHello(name) {
var name = name || 'World';
return 'Hello ' + name + '!';
}
console.log(sayHello()); // Hello World!
console.log(sayHello('John')); // Hello John!

Arrow Functions

Arrow Functions are another interesting feature in ES6. It provide a concise and more readable way to write functions in JavaScript. They are particularly useful for defining functions that are short and don’t require complex logic.

Arrow functions are defined using a new syntax, the fat arrow (=>) notation. Let's see how it looks:

// Function Expression
const sum = function(a, b) {
return a + b;
}
console.log(sum(2, 3)); // 5

// Arrow function
const sum = (a, b) => a + b;
console.log(sum(2, 3)); // 5

As you can see there is no function and return keyword in arrow function declaration.

You can also skip the parentheses i.e. () in case when there is exactly one parameter, but you will always need to use it when you have zero or more than one parameter.

Additionally, if there’s more than one expression in the function body, you need to wrap it braces ({}). In this case you also need to use the return statement to return a value.

There are several variations of how you can write arrow functions. Here are the most commonly used:

// Single parameter, single statement
var greet = name => console.log("Hi " + name + "!");
greet("Peter"); // Hi Peter!

// Multiple arguments, single statement
var multiply = (x, y) => x * y;
console.log(multiply(2, 3)); // 6

// Single parameter, multiple statements
var test = age => {
if(age > 18) {
console.log("Adult");
} else {
console.log("Teenager");
}
}
test(21); // Adult
// Multiple parameters, multiple statements
var divide = (x, y) => {
if(y != 0) {
return x / y;
}
}
console.log(divide(10, 2)); // 5
// No parameter, single statement
var hello = () => console.log('Hello World!');
hello(); // Hello World!

this with Arrow Function

In normal functions, a this variable is created which references the objects that call them.

However, this is not associated with arrow functions. Arrow function does not have its own this. So whenever you call this, it refers to its parent scope. For example,

Inside a regular function

const obj = {
name: 'deeecode',
age: 200,
print: function() {
console.log(this)
}
}

obj.print()
// {
// name: 'deeecode',
// age: 200,
// print: [Function: print]
// }

As you can see here, the this in the print method points to obj, which is the object that calls the method.

Here’s another example:

const obj = {
name: 'deeecode',
age: 200,
print: function() {
function print2() {
console.log(this)
}

print2()
}
}
obj.print()
// Window

Here, we have two functions. The first one is print which is a method of the obj object. The second is print2 which is a function declared inside print. print2() is also called directly.

In this case, print is called by obj (obj.print()) but no object calls print2 (print2()). So the this in print2 would reference the window object by default.

Get Kevin Mavani’s stories in your inbox

Join Medium for free to get updates from this writer.

Now let’s see what happens with an arrow function.

const obj = {
name: 'deeecode',
age: 200,
print: () => {
console.log(this)
}
}
obj.print()
// Window

By using an arrow function for print, this function does not automatically create a this variable. As a result, any reference to this would point to what this was before the function was created.

As you see in the result, this was pointing to the Window object before print was created.

Let’s see another example:

const obj = {
name: 'deeecode',
age: 200,
print: function() {
const print2 = () => {
console.log(this)
}

print2()
}
}
obj.print()
// {
// name: 'deeecode',
// age: 200,
// print: [Function: print]
// }

Here, we have print as a normal function which means a this variable is automatically created in it. Then we have print2 which is an arrow function.

Because obj is calling print (as in obj.print()), the this in print would point to obj.

Since print2 is an arrow function, it doesn't create its own this variable. Therefore, any reference to this would point to what the value of this was before the function was created. In this case where obj calls print, this was pointing to obj before print2 was created. As you can see in the results, by logging this from print2, obj is the result.

Modules

Prior to ES6, there were no native support for modules in JavaScript. Everything inside a JavaScript application.

ES6 introduces file based module, in which each module is represented by a separate .js file. Now, you can use the export or import statement in a module to export or import variables, functions, classes or any other entity to/from other modules or files.

Let’s create a module i.e. a JavaScript file “main.js” and place the following code in it:

let greet = "Hello World!";
const PI = 3.14;

function multiplyNumbers(a, b) {
return a * b;
}
// Exporting variables and functions
export { greet, PI, multiplyNumbers };

Now create another JavaScript file “app.js” with the following code:

import { greet, PI, multiplyNumbers } from './main.js';

console.log(greet); // Hello World!
console.log(PI); // 3.14
console.log(multiplyNumbers(6, 15)); // 90

The Rest Parameters

ES6 introduces rest parameters that allow us to pass an arbitrary number of parameters to a function in the form of an array. This is particularly helpful in situations when you want to pass parameters to a function but you have no idea how many you will need.

To declare a rest parameter, you use three dots (...) followed by the parameter name. Rest parameters collect any additional arguments passed to the function into an array. Take a look at the following example, to see how it works:

function sum(...numbers) {
let result = 0;
for (const num of numbers) {
result += num;
}
return result;
}

console.log(sum(1, 2, 3, 4, 5)); // Output: 15

When the rest parameter is the only parameter in a function, it gets all the arguments passed to the function, otherwise it gets the rest of the arguments that exceeds the number of named parameters.

function myFunction(a, b, ...args) {
return args;
}
console.log(myFunction(1, 2, 3, 4, 5)); // 3,4,5
console.log(myFunction(-7, 5, 0, -2, 4.5, 1, 3)); // 0,-2,4.5,1,3

Key Points:

  1. Rest parameters must come after regular parameters in the function’s parameter list.
  2. You can only have one rest parameter in a function.
  3. Rest parameters are real arrays, so you can use array methods like map, filter, or forEach on them.
  4. Rest parameters are useful when you want to accept an arbitrary number of arguments without having to specify each argument individually.

The Spread Operator

The spread operator, which is also denoted by (...), performs the exact opposite function of the rest operator. The spread operator spreads out (i.e. splits up) an array and passes the values into the specified function, as shown in the following example:

function addNumbers(a, b, c) {
return a + b + c;
}

let numbers = [5, 12, 8];
// ES6 spread operator
console.log(addNumbers(...numbers)); // 25

The spread operator can also be used to insert the elements of an array into another array without using the array methods like push(), unshift() concat(), etc.

let pets = ["Cat", "Dog", "Parrot"];
let bugs = ["Ant", "Bee"];

// Creating an array by inserting elements from other arrays
let animals = [...pets, "Tiger", "Wolf", "Zebra", ...bugs];
console.log(animals); // Cat,Dog,Parrot,Tiger,Wolf,Zebra,Ant,Bee

Destructuring Assignment

The destructuring assignment is an expression that makes it easy to extract values from arrays, or properties from objects, into distinct variables by providing a shorter syntax.

There are two kinds of destructuring assignment expressions — the array and object destructuring assignment. Well, let’s see how each of them exactly works:

The array destructuring assignment

Prior to ES6, to get an individual value of an array we need to write something like this:

// ES5 syntax
var fruits = ["Apple", "Banana"];
var a = fruits[0];
var b = fruits[1];
console.log(a); // Apple
console.log(b); // Banana

In ES6, we can do the same thing in just one line using the array destructuring assignment:

// ES6 syntax
let fruits = ["Apple", "Banana"];
let [a, b] = fruits; // Array destructuring assignment
console.log(a); // Apple
console.log(b); // Banana

You can also use rest operator in the array destructuring assignment, as shown here:

// ES6 syntax
let fruits = ["Apple", "Banana", "Mango"];
let [a, ...r] = fruits;
console.log(a); // Apple
console.log(r); // Banana,Mango
console.log(Array.isArray(r)); // true

The object destructuring assignment

In ES5 to extract the property values of an object we need to write something like this:

// ES5 syntax
var person = {name: "Peter", age: 28};
var name = person.name;
var age = person.age;
console.log(name); // Peter
console.log(age); // 28

But in ES6, you can extract object’s property values and assign them to the variables easily like this:

// ES6 syntax
let person = {name: "Peter", age: 28};
let {name, age} = person; // Object destructuring assignment
console.log(name); // Peter
console.log(age); // 28

Conclusion:

In conclusion, ES6, with its array of powerful features like arrow functions, template literals, and block-scoped variables, has fundamentally transformed JavaScript development. This evolution has empowered developers to write cleaner, more efficient, and maintainable code, contributing to the ongoing success and adaptability of JavaScript in the ever-evolving landscape of web development.

If you’ve made it till here, thanks for giving this a read, have a great day! :)

--

--