JavaScript ES6+ Features

Write modern, cleaner, and more maintainable JavaScript.

arrowdestructuringspread/rest

Table of Contents

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
Featurevarletconst
ScopeFunctionBlockBlock
HoistingYes (undefined)Yes (TDZ)Yes (TDZ)
ReassignmentYesYesNo
RedeclarationYesNoNo

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 GC

12. 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

FeatureBefore ES6ES6+Benefit
Variablesvar onlylet, constBlock scoping, safer bindings
Functionsfunction keywordArrow functionsConcise syntax, lexical this
Strings+ concatenationTemplate literalsReadable interpolation
ObjectsManual assignmentShorthand/computed namesLess boilerplate
AsyncCallbacksPromises, async/awaitAvoid callback hell
ModulesScript tags/IIFEimport/exportBetter modularity
CollectionsArrays/ObjectsMap/SetBetter 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.

10 ES6+ Interview Q&A

10 ES6+ MCQs