JavaScript ES6+ Features
Write modern, cleaner, and more maintainable JavaScript.
arrowdestructuringspread/restTable of Contents
- Intro
- Variable Declarations: let and const
- Arrow Functions
- Template Literals
- Destructuring Assignment
- Spread and Rest Operators
- Default Parameters
- Enhanced Object Literals
- Classes
- Promises and Async/Await
- Modules (import/export)
- Map and Set
- Iterators and Generators
- Practical Examples
- ES6 Features Comparison
- What's Next After ES6?
- Interview Q&A
- MCQ
JavaScript ES6 Tutorial: A Complete Guide for 2026
JavaScript ES6 (ECMAScript 2015) was a major milestone in the language's evolution, introducing features that fundamentally changed how developers write JavaScript. Even with newer versions available today, ES6 remains the foundation of modern JavaScript development.
In this guide, you will learn all essential ES6 features with examples and practical usage.
1. Variable Declarations: let and const
let and const fix common scoping and reassignment problems from var.
// let is block-scoped
if (true) {
let blockScoped = "I'm only inside this block";
var functionScoped = "I'm accessible outside too";
}
console.log(functionScoped);
// console.log(blockScoped); // ReferenceError
// Temporal Dead Zone (TDZ)
// console.log(myVar); // ReferenceError
let myVar = "Hello";
const PI = 3.14159;
const user = { name: "Alice", age: 25 };
user.age = 26; // allowed (object mutated)
// user = {}; // TypeError| Feature | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Hoisting | Yes (undefined) | Yes (TDZ) | Yes (TDZ) |
| Reassignment | Yes | Yes | No |
| Redeclaration | Yes | No | No |
2. Arrow Functions
Arrow functions are concise and lexically bind this.
const sayHello = () => console.log("Hello!");
const double = x => x * 2;
const add = (a, b) => a + b;
const getFullName = (firstName, lastName) => {
const fullName = `${firstName} ${lastName}`;
return fullName;
};
const arrowObject = {
name: "Arrow",
greet: function () {
setTimeout(() => console.log(`Hello from ${this.name}`), 100);
}
};
// Avoid arrow for methods requiring dynamic this
const person = {
name: "Bob",
greet: () => console.log(`Hi, I'm ${this.name}`),
sayName: function () { console.log(`Hi, I'm ${this.name}`); }
};3. Template Literals
const name = "Alice";
const age = 30;
const greeting = `Hello, my name is ${name} and I'm ${age} years old.`;
const multiline = `This is line one
This is line two
This is line three`;
function highlight(strings, ...values) {
return strings.reduce((result, str, i) =>
result + str + (values[i] ? `${values[i]}` : ""), "");
}
const output = highlight`Hello ${name}, welcome to ${"JavaScript"} tutorial!`;4. Destructuring Assignment
const colors = ["red", "green", "blue"];
const [first, second] = colors;
const [, , lastColor] = colors;
const [head, ...tail] = [1, 2, 3, 4, 5];
let x = 1, y = 2;
[x, y] = [y, x];
const user = { name: "John", age: 28, city: "Boston" };
const { name: userName, city: location, role = "user" } = user;
const employee = { personalInfo: { firstName: "Jane", lastName: "Smith" } };
const { personalInfo: { firstName, lastName } } = employee;
function printUser({ name, age }) {
console.log(`${name} is ${age} years old`);
}5. Spread and Rest Operators
... can expand values (spread) or collect values (rest).
// Spread
const combined = [...[1, 2, 3], ...[4, 5, 6]];
const copy = [...combined];
const merged = { ...{ a: 1, b: 2 }, ...{ c: 3 } };
const max = Math.max(...[3, 5, 1, 8, 2]);
// Rest
function logAll(first, second, ...rest) {
console.log(first, second, rest);
}
const [first, ...remaining] = [10, 20, 30, 40];
const person = { name: "Emma", age: 32, city: "London", job: "Engineer" };
const { name, ...details } = person;6. Default Parameters
function greet(name = "Guest") {
return `Hello, ${name}!`;
}
function createUser(username = "anonymous", isAdmin = false, age = 18) {
return { username, isAdmin, age };
}
function calculatePrice(basePrice, tax = basePrice * 0.1) {
return basePrice + tax;
}
function registerUser({ username = "anon", email = "noemail@example.com" } = {}) {
return `User: ${username}, Email: ${email}`;
}7. Enhanced Object Literals
const name = "Alice";
const age = 30;
const newUser = { name, age }; // property shorthand
const calculatorES6 = {
add(a, b) { return a + b; },
subtract(a, b) { return a - b; },
multiply: (a, b) => a * b
};
const dynamicKey = "userRole";
const obj = {
[dynamicKey]: "admin",
[`id_${123}`]: true
};8. Classes
class Animal {
constructor(name, species) { this.name = name; this.species = species; }
speak() { console.log(`${this.name} makes a sound`); }
get description() { return `${this.name} is a ${this.species}`; }
set setName(newName) { if (newName.length > 0) this.name = newName; }
static compareAnimals(a1, a2) { return a1.name === a2.name; }
}
class Dog extends Animal {
constructor(name, breed) { super(name, "Dog"); this.breed = breed; }
speak() { console.log(`${this.name} barks loudly!`); }
fetch() { console.log(`${this.name} is fetching the ball`); }
}
class BankAccount {
#balance = 0;
constructor(initialBalance) { this.#balance = initialBalance; }
deposit(amount) { if (amount > 0) this.#balance += amount; }
getBalance() { return this.#balance; }
}9. Promises and Async/Await
const fetchData = () => new Promise((resolve, reject) => {
setTimeout(() => resolve({ data: "Here's your data", status: 200 }), 1000);
});
fetchData()
.then(result => result.data.toUpperCase())
.then(processed => console.log(processed))
.catch(error => console.error(error))
.finally(() => console.log("Operation completed"));
async function fetchUserData(userId) {
try {
const user = await getUser(userId);
const orders = await getOrders(user.id);
return orders;
} catch (error) {
console.error(error);
throw error;
}
}
Promise.all([getUser(1), getUser(2)]);
Promise.allSettled([getUser(1), getUser(2)]);
Promise.race([fetchFromAPI1(), fetchFromAPI2()]);10. Modules (import/export)
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
const divide = (a, b) => a / b;
export { divide };
// user.js
export default class User {
constructor(name, email) { this.name = name; this.email = email; }
}
export const API_KEY = "abc123";
// main.js
import User, { API_KEY } from "./user.js";
import { add, divide as division } from "./math.js";
import * as MathUtils from "./math.js";
// Dynamic import
const module = await import("./heavy-module.js");
module.doSomething();11. New Data Structures: Map and Set
const userRoles = new Map();
userRoles.set("john", "admin");
userRoles.set("jane", "editor");
console.log(userRoles.get("john"));
const scores = new Map([["Alice", 95], ["Bob", 87]]);
for (const [key, value] of scores) console.log(key, value);
const unique = [...new Set([1, 2, 2, 3, 3, 4])];
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
const union = new Set([...setA, ...setB]);
const intersection = new Set([...setA].filter(x => setB.has(x)));
const cache = new WeakMap();
let user = { id: 1 };
cache.set(user, { name: "Alice" });
user = null; // eligible for GC12. Iterators and Generators
class Range {
constructor(start, end) { this.start = start; this.end = end; }
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return { next() { return current <= end ? { value: current++, done: false } : { value: undefined, done: true }; } };
}
}
function* fibonacci() {
let a = 0, b = 1;
while (true) { yield a; [a, b] = [b, a + b]; }
}
function* generateNumbers() {
yield 1;
yield 2;
yield* [3, 4, 5];
yield 6;
}13. Practical Examples
Example 1: User Management System
class User {
#password;
constructor(username, email, password) {
this.username = username; this.email = email; this.#password = password; this.createdAt = new Date();
}
verifyPassword(input) { return input === this.#password; }
}
class UserManager {
constructor() { this.users = new Map(); }
addUser(user) { if (this.users.has(user.email)) throw new Error("User already exists"); this.users.set(user.email, user); }
getStats() { return { totalUsers: this.users.size }; }
}Example 2: Data Fetching with Error Handling
const API = {
async fetch(endpoint, options = {}) {
try {
const response = await fetch(`https://api.example.com${endpoint}`, { ...options });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return { success: true, data: await response.json() };
} catch (error) {
return { success: false, error: error.message };
}
}
};Example 3: Shopping Cart System
class ShoppingCart {
#notifyUpdate() { console.log("Cart updated"); }
constructor() { this.items = new Map(); this.discountCode = null; }
addItem(id, name, price, quantity = 1) { this.items.set(id, { id, name, price, quantity }); this.#notifyUpdate(); }
calculateTotal() { return [...this.items.values()].reduce((sum, i) => sum + i.price * i.quantity, 0); }
}Summary: ES6 Features Comparison
| Feature | Before ES6 | ES6+ | Benefit |
|---|---|---|---|
| Variables | var only | let, const | Block scoping, safer bindings |
| Functions | function keyword | Arrow functions | Concise syntax, lexical this |
| Strings | + concatenation | Template literals | Readable interpolation |
| Objects | Manual assignment | Shorthand/computed names | Less boilerplate |
| Async | Callbacks | Promises, async/await | Avoid callback hell |
| Modules | Script tags/IIFE | import/export | Better modularity |
| Collections | Arrays/Objects | Map/Set | Better key support and uniqueness |
What's Next After ES6?
After mastering ES6, continue with modern JavaScript features such as optional chaining, nullish coalescing, private class members, top-level await, and advanced async patterns. Also practice tooling with Babel, bundlers, and TypeScript for real-world projects.
Related: Modules, Asynchronous JavaScript, Projects.