JavaScript ES6 Simplified

JavaScript ES6 Simplified

I resumed coding after a gap of 4 months and needless to say, I struggled to recall the syntax of arrow functions in first session. If you are someone like me, who is looking for a quick refresher for the ES6 topics explained in a simple and concise manner, you are at the right place.

We will be focusing more on syntax than semantics. Without further ado, let's explore ES6.

Some Basics To Get You Started:

What is ES6?

ES6 was one major revision made to JavaScript in 2015 which introduced most of the new syntax that we will be covering in this article. Since 2015, a major version of JavaScript is released every June. The 13th and current version, ECMAScript 2022 was released in June last year.

Difference Between Primitive and Non-Primitive Data Types

In JavaScript, a primitive (primitive value, primitive data type) is data that is not an object and has no methods or properties. - MDN

There are total 7 primitive(basic) data types in JS

  • Null

  • Number

  • String

  • Symbol

  • Undefined

  • Boolean

  • BigInt

Object is a non-primitive data type in JavaScript.

Difference Between Declaring, Re-assigning and Re-declaring a Variable

  • Declaring a Variable

We can simply declare a variable using var, let or const keywords. When we declare a variable we reserve space for that variable in memory, but that space is empty.

When we initialize it with some value, we fill that empty space with that value. This is also called as assigning a value to the variable.

// Example 1: Simply Declaring a Variable 

let a;

// Example 2: Declaring a Variable and Initializing it with Value 

let a= 25;
  • Reassigning a Value

Once we have already assigned value to variable, we can reassign the value to that variable, provided we are using the var or let keywords.

const cannot be reassigned with some value, but objects ( functions and arrays) assigned to a variable using const are still mutable( can be updated/reassigned values). Using the const declaration only prevents reassignment of the variable identifier.

Let’s understand this with example.

EXAMPLE 1: REASSIGNING A VALUE USING LET: 
// declaring a variable and initializing a variable with value. 
// this is also called assigning a variable a value. 
let a = 25; 

// this is called re-assigning value to the variable. when a variable is already declared
// and if we try to give it another value, we are re-assigning value to it. 
a = 26; 

EXAMPLE 2: REASSIGNING/MUTATING A VALUE DECLARED USING CONST:

const z = [7, 8, 9];
z = [1, 2, 3];  // This will throw an error as we cannot use z again to point to s different array
z[1] = 85;   // This is an example of mutating or updating a value in array declared using const
console.log(z);
  • Re-declaring a Variable

This can only be done using let and var keywords. For this we also need to know scoping, which we will cover next.

EXAMPLE 1: REDECLARING A VARIABLE USING LET

let a= 34; // declaring a variable

let a= 25; // Re-declaring the value that has already been declared.

Scopes in JavaScript

Have you ever taken an exam where one question came from outside the scope of the syllabus?

Scopes in JavaScript work in a similar fashion. Each var, let and const variable is declared within its own scope and is not visible outside of that scope.

There are five major scopes in JavaScript: global scope, module scope, function scope, block scope and lexical scope. We are only concerned with 3 right now.

  • Global Scope

This is the root scope. Variables which are defined outside any function, block, or module scope have global scope. Variables in this scope are accessible from every scope.

  • Function Scope

Function scope means that parameters and variables declared inside a function can be seen everywhere within the function, but not outside of it.

Variables declared with Var have only function scope and are hoisted to the top of their scope. This is the reason they can be accessed even before being declared. See this example:

function myFunc(){
  console.log(x);
  var x = 1;   // the value is assigned later but the empty space created for var is accessible within function
}

myFunc(); // Returns undefined

This is not the case with let keyword. The variable declared using let can only be accessed only after its definition.

function myFunc(){
  console.log(x);
  let x = 1;
}

myFunc();
//Uncaught ReferenceError: x is not defined
  • Block Scope

It is defined using curly braces { and }. Variables declared using let and const by default have block scope. They can only be accessed within that block.

Lets see one example of let block scope:

let a = 1;
{ 
  let a = 2; // Not accessible outside this scope
}
console.log(a); //1

But, in contrast var has no block scope:

var a = 1;
{ 
  var a = 2;  // It is hoisted/bubbled to the top as var has no block scope
}
console.log(a); // Returns 2

Section 1: Let, Const and Var

Var used to be the default way to store variables in JS but this changed after ES6. Let and Const were introduced to overcome some of the shortcomings of var keyword.

Lets understand some shortcomings of the Var keyword:

  1. It is globally scoped

  2. It is easily overwritten . Var can be re-declared and updated within its scope.

  3. Can cause unintended bugs in your codebase and hence it is not preferred.

A variable declared with var can be re-declared multiple times in the same scope. The following code works just fine:

function myFunc(){
  var x = 1
  var x = 2;
  console.log(x);
}

myFunc();

Variables declared with let or const cannot be re-declared in the same scope:

function doSomething(){
  let x = 1
  let x = 2;
}
//Uncaught SyntaxError: Identifier 'x' has already been declared

Section 2: Arrow Functions

In JavaScript, we don't usually need to assign a name to functions, particularly when passing them as arguments to other functions. Instead, we use inline functions which don't require a name as they aren't used anywhere else. These functions are called Arrow Functions and allow us to write functions in a concise and direct way.

// ES5 Syntax

const myFunc = function() {
  const myVar = "value";
  return myVar;
}

// ES6 Syntax for Arrow Functions

const myFunc = () => {
  const myVar = "value";
  return myVar;
}

When no function body is present and only a return value is specified, arrow function syntax allows omitting the keyword return and the brackets enclosing the code. This helps to simplify smaller functions into single-line statements.

const myFunc = () => "value";  // Returs string "value" by default

Just like regular functions, we can add arguments into an arrow function

EXAMPLE 1:

const triple = (item) => item * 3;
triple(3);   // Returns 9

EXAMPLE 2:
// If an arrow function has a single parameter, the parentheses enclosing the parameter may be omitted.

const double = item => item * 2;

EXAMPLE 3:
//It is possible to pass more than one argument into an arrow function.

const multiplier = (item, multi) => item * multi;
multiplier(4, 2);

Section 3: Rest and Spread

Both Rest Parameter and Spread Operators are identified by the three dots syntax(…) and can initially seem confusing to understand. But let’s demystify the Rest and Spread parameter once and for all.

  • Rest Parameter ( To access rest of the values)

Using the Rest parameter, we can create functions that take a variable number of arguments. These arguments are stored in an array and can be accessed from within the function.

Check out this example:

function howMany(...args) {
  return "You have entered " + args.length + " arguments.";
}
console.log(howMany(0, 1, 2));   // Returns > You have passed 3 arguments
console.log(howMany("string", null, [1, 2, 3], { }));  // Returns > You have passed 4 arguments

Rest Parameter gives us flexibility to use functions where the number of arguments are variable.

  • Spread Operator ( To Evaluate Arrays In-Place)

ES6 introduced the spread operator, which enables us to expand arrays and other expressions wherever multiple parameters or elements are expected.

...arr returns an unpacked array. In other words, it spreads the array. However, the spread operator only works in-place, like in an argument to a function or in an array literal. The following code will not work:

const spreaded = ...arr;

To appreciate Spread Operator, lets understand the syntax that was in place in ES5 to calculate the max value in an array:

var arr = [1,2,3,4];
var maximum = Math.max.apply(null, arr); // Returns 4

We had to use Math.max.apply(null, arr) instead of Math.max(arr) since it returns NaN. Math.max() requires comma-separated arguments, not an array. The spread operator makes this syntax more readable and maintainable.

We can write the above code simply as follows:

const arr = [1,2, 3, 5];
const maximus = Math.max(...arr);   // Returns 5

Check out this example to copy content of one array to another:

const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];
let arr2;

arr2 = [...arr1]; 

console.log(arr2);  // Returns ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];

Spread Operator simply obliterates the boundary of array or object and spreads the elements.

Section 4: Destructuring

Destructuring is a feature in JavaScript that allows you to extract values from arrays or objects and assign them to variables in a more concise and readable way. Here's an example to illustrate how destructuring works:

// Destructuring an array
const numbers = [1, 2, 3, 4];
const [a, b, c, d] = numbers;
console.log(a); // Output: 1
console.log(b); // Output: 2
console.log(c); // Output: 3
console.log(d); // Output: 4

// Destructuring an object
const person = { name: 'John', age: 30, location: 'New York' };
const { name, age, location } = person;
console.log(name); // Output: 'John'
console.log(age); // Output: 30
console.log(location); // Output: 'New York'

In the array destructuring example, we create an array numbers with four values. Then, we use destructuring to assign each value to a separate variable a, b, c, and d. This is equivalent to writing const a = numbers[0]; const b = numbers[1]; const c = numbers[2]; const d = numbers[3];.

In the object destructuring example, we create an object person with three properties. Then, we use destructuring to extract the values of each property and assign them to separate variables with the same name. This is equivalent to writing const name = person.name; const age = person.age; const location = person.location;.

Destructuring can be useful for quickly accessing values in complex data structures, such as nested objects or arrays. It can also make your code more readable by eliminating repetitive property or index access.

Section 5: Template literals

ES6 introduces a powerful new type of string: template literals. They make creating complex strings much easier.

Template literals enable multi-line strings and string interpolation features. For example, the following code:

const person = {
  name: "Mary",
  age: 20
};

const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;

console.log(greeting); // returns >> Hello, my name is Mary! and I am 20 years old.

will print out: Hello, my name is Mary! and I am 20 years old..

Two key points to note here: backticks (```) are used to wrap the string, not single or double quotes; and the string is multi-line both in the code and the output. This eliminates the need for \\\\n within strings. The ${variable} syntax allows for variables to be dropped into strings, rather than having to use concatenation with the + operator. Furthermore, other expressions can be included, e.g. ${a + b}, providing more flexibility to create robust strings.

Section 6: Modules, Import and Export

  • Modules

The codebase of modern websites is huge and for this reason modules were introduced in JavaScript to breakdown the codebase into smaller, cleaner and maintainable chunks.

You can export parts of a file to use in other files, and import the parts you need, wherever you need them. To do this, create a script in your HTML document with a type of module. Here's an example:

// HTML Document

<html>
  <body>

<script type="module" src="filename.js"></script>

  </body>
</html>

A script that uses this module type can now use the import and export features that are provided in ES6.

  • Use Export to Share a Code Block ( Named Export)

Let’s take an example of file that contains math functions that we need to export to a different file.

// File name = math_functions.js

const add = (x, y) => {
  return x + y;
}

const subtract = (x, y) => {
  return x - y;
}

const multiply = (x, y) => {
  return x * y;
}

export { add, subtract };  // We use this to named export just the add and subtract functions
  • Use Import to Reuse the Above Exported Code

import allows us to choose which parts of a file or module to load.

Let’s see this in action:

// Importing only add and subtract function from the above file
import { add, subtract } from './math_functions.js';
  • To import Everything from a File

When we import everything from a file, we create an object and name it anything we want. In this case, we named it mathModule.

To access functions from mathModule Object we use the same way as we would do with any other JavaScript Object.

// To Import Everything from File

import * as mathModule from "./math_functions.js";

// TO use Add and Subtract Functions that were imported, call the Object

mathModule.add(7,3);
mathModule.subtract(45,3);
  • Creating an Export Fallback with export default

There are 2 types of Export and we earlier saw the example for named export. This allows us to make multiple functions and variables available for use in other files.

There is another export syntax you need to know, known as export default.

We typically use this syntax when exporting a single value from a file. It can also be used to create a default value for a file or module.

// Example 1: Named Export Function

export default function add(x, y) {
  return x + y;
}

// Example 2: Anonymous Export Function

export default function(x, y) {
  return x + y;
}

export default is used to declare a fallback value for a module or file, and only one value can be a default export per module or file. It is not possible to use export default with var, let, or const.

  • Import a Default Export

We learned above about export default and its uses.

To import a default export, you must use a different import syntax. For example, add is the default export of the math_functions.js file. To import it, use the following syntax:

// Example 1: Import a Default Export

import add from "./math_functions.js";  // No curly braces are used

add is not enclosed by curly braces ({}) when imported from math_functions.js . We can use any name for a default import.

Conclusion

So it’s a wrap. Now I’d like to hear from you.

Is there any specific topic in ES6 that you struggled with? If so, did this article help in any way?

Let me know in the comments section below or you can always reach out to me on Twitter or Discord. Even I am learning, so if you reach out to me either I’ll help or we’ll learn something new together.