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:
It is globally scoped
It is easily overwritten . Var can be re-declared and updated within its scope.
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.