JavaScript ES6 Overview

ES6 (ECMAScript 2015) was a major update to JavaScript that introduced many powerful features. This guide covers the most important ES6+ features that every modern JavaScript developer should know.

Try It Yourself

Experiment with the key ES6 features:

index.js
// ES6 Features Overview - Try them out!

// 1. let and const
const PI = 3.14159;
let count = 0;
count++;

// 2. Arrow functions
const greet = (name) => `Hello, ${name}!`;
const double = x => x * 2;

// 3. Template literals
const user = { name: "Alice", age: 25 };
console.log(`${user.name} is ${user.age} years old`);

// 4. Destructuring
const { name, age } = user;
const [first, second] = [1, 2, 3];
console.log("Destructured:", name, first);

// 5. Spread operator
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log("Spread:", arr2);

// 6. Default parameters
const power = (base, exp = 2) => base ** exp;
console.log("Power:", power(3)); // 9

// 7. Classes
class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(`${this.name} makes a sound`);
  }
}

const dog = new Animal("Rex");
dog.speak();

let and const

Block-scoped variable declarations that replace var:

javascript
// let - block-scoped, can be reassigned
let count = 0;
count = 1; // OK

if (true) {
  let blockVar = "I'm block-scoped";
  console.log(blockVar); // Works
}
// console.log(blockVar); // Error: not defined

// const - block-scoped, cannot be reassigned
const PI = 3.14159;
// PI = 3; // Error: Assignment to constant

// const objects can be mutated
const user = { name: "Alice" };
user.name = "Bob"; // OK - mutating, not reassigning
// user = {}; // Error - reassigning

// Use const by default, let when needed, avoid var
Best Practice
Use const by default. Only use let when you need to reassign the variable. Avoid var in modern JavaScript.

Arrow Functions

A shorter syntax for writing functions:

javascript
// Regular function
function add(a, b) {
  return a + b;
}

// Arrow function
const addArrow = (a, b) => a + b;

// Single parameter - no parentheses needed
const double = x => x * 2;

// No parameters - empty parentheses required
const getRandom = () => Math.random();

// Multiple statements - need braces and return
const process = (x) => {
  const doubled = x * 2;
  const squared = doubled ** 2;
  return squared;
};

// Returning objects - wrap in parentheses
const createUser = (name) => ({ name, id: Date.now() });

console.log(addArrow(2, 3));    // 5
console.log(double(4));          // 8
console.log(createUser("Alice")); // { name: "Alice", id: ... }

Template Literals

Multi-line strings and expression interpolation with backticks:

javascript
const name = "Alice";
const age = 25;

// Old way - string concatenation
const old = "Hello, " + name + "! You are " + age + " years old.";

// Template literals - use backticks
const modern = `Hello, ${name}! You are ${age} years old.`;

// Multi-line strings
const multiline = `
  This is a
  multi-line
  string
`;

// Expressions inside ${}
const price = 19.99;
const quantity = 3;
console.log(`Total: $${(price * quantity).toFixed(2)}`);
// "Total: $59.97"

// Tagged templates (advanced)
function highlight(strings, ...values) {
  return strings.reduce((result, str, i) => {
    return result + str + (values[i] ? `**${values[i]}**` : "");
  }, "");
}

const highlighted = highlight`Hello ${name}, you are ${age}`;
// "Hello **Alice**, you are **25**"

Destructuring

Extract values from objects and arrays into variables:

javascript
// Object destructuring
const user = { name: "Alice", age: 25, city: "NYC" };

const { name, age } = user;
console.log(name, age); // "Alice" 25

// Renaming
const { name: userName } = user;
console.log(userName); // "Alice"

// Default values
const { country = "USA" } = user;
console.log(country); // "USA"

// Nested destructuring
const company = {
  name: "TechCorp",
  address: { city: "SF", zip: "94102" }
};
const { address: { city } } = company;
console.log(city); // "SF"

// Array destructuring
const colors = ["red", "green", "blue"];
const [first, second] = colors;
console.log(first, second); // "red" "green"

// Skip elements
const [, , third] = colors;
console.log(third); // "blue"

// Rest pattern
const [head, ...tail] = colors;
console.log(tail); // ["green", "blue"]

// Swap variables
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1

Spread and Rest Operators

The ... operator for expanding or collecting elements:

javascript
// Spread operator (...) - expands elements

// Array spread
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]

// Copy array
const copy = [...arr1];

// Merge arrays
const merged = [...arr1, ...arr2];

// Object spread
const defaults = { theme: "dark", lang: "en" };
const settings = { ...defaults, lang: "es" };
// { theme: "dark", lang: "es" }

// Function arguments
const nums = [1, 2, 3];
console.log(Math.max(...nums)); // 3

// Rest parameters (...) - collects elements
function sum(...numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

// Rest in destructuring
const [first, ...rest] = [1, 2, 3, 4];
console.log(rest); // [2, 3, 4]

const { name, ...others } = { name: "Alice", age: 25, city: "NYC" };
console.log(others); // { age: 25, city: "NYC" }

Default Parameters

Set default values for function parameters:

javascript
// Default parameter values

// Old way
function greetOld(name) {
  name = name || "Guest";
  return "Hello, " + name;
}

// ES6 way
function greet(name = "Guest") {
  return `Hello, ${name}`;
}

console.log(greet());        // "Hello, Guest"
console.log(greet("Alice")); // "Hello, Alice"

// Expressions as defaults
function createId(prefix = "id", num = Date.now()) {
  return `${prefix}_${num}`;
}

// Using previous parameters
function rectangle(width, height = width) {
  return width * height;
}
console.log(rectangle(5)); // 25 (square)

// Destructuring with defaults
function createUser({ name = "Anonymous", age = 0 } = {}) {
  return { name, age };
}
console.log(createUser());                // { name: "Anonymous", age: 0 }
console.log(createUser({ name: "Bob" })); // { name: "Bob", age: 0 }

Classes

Syntactic sugar for constructor functions and prototypes:

javascript
// ES6 Classes

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a sound`);
  }

  // Getter
  get info() {
    return `Animal: ${this.name}`;
  }

  // Static method
  static isAnimal(obj) {
    return obj instanceof Animal;
  }
}

// Inheritance
class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Call parent constructor
    this.breed = breed;
  }

  speak() {
    console.log(`${this.name} barks!`);
  }

  fetch() {
    console.log(`${this.name} fetches the ball`);
  }
}

const dog = new Dog("Rex", "German Shepherd");
dog.speak();  // "Rex barks!"
dog.fetch();  // "Rex fetches the ball"
console.log(dog.info); // "Animal: Rex"
console.log(Animal.isAnimal(dog)); // true

Modules

Native import/export for organizing code:

javascript
// ES6 Modules (import/export)

// Named exports (math.js)
export const PI = 3.14159;
export function add(a, b) {
  return a + b;
}
export function subtract(a, b) {
  return a - b;
}

// Named imports
import { add, subtract } from './math.js';
import { add as addition } from './math.js'; // Rename
import * as math from './math.js'; // Import all

// Default export (user.js)
export default class User {
  constructor(name) {
    this.name = name;
  }
}

// Default import (any name works)
import User from './user.js';
import MyUser from './user.js'; // Same thing

// Mixed
export default function main() {}
export const helper = () => {};

import main, { helper } from './module.js';
Module Support
ES modules work in all modern browsers with type="module" and in Node.js with .mjs extension or "type": "module" in package.json.

Object Shorthand

Cleaner object literal syntax:

javascript
// Object property shorthand
const name = "Alice";
const age = 25;

// Old way
const userOld = { name: name, age: age };

// Shorthand - when variable name matches property name
const user = { name, age };

// Method shorthand
const calculator = {
  // Old way
  add: function(a, b) {
    return a + b;
  },

  // Shorthand
  subtract(a, b) {
    return a - b;
  }
};

// Computed property names
const key = "dynamicKey";
const obj = {
  [key]: "value",
  ["computed_" + key]: "another value"
};
console.log(obj.dynamicKey); // "value"
console.log(obj.computed_dynamicKey); // "another value"

Promises

Handle asynchronous operations:

javascript
// Promises - handle async operations

// Creating a promise
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = true;
      if (success) {
        resolve({ data: "Hello!" });
      } else {
        reject(new Error("Failed to fetch"));
      }
    }, 1000);
  });
};

// Using promises
fetchData()
  .then(result => {
    console.log("Success:", result.data);
    return result.data.toUpperCase();
  })
  .then(upper => {
    console.log("Uppercase:", upper);
  })
  .catch(error => {
    console.error("Error:", error.message);
  })
  .finally(() => {
    console.log("Done!");
  });

// Promise.all - wait for all
Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
]).then(values => console.log(values)); // [1, 2, 3]

// Promise.race - first to complete
Promise.race([
  new Promise(r => setTimeout(() => r("slow"), 200)),
  new Promise(r => setTimeout(() => r("fast"), 100))
]).then(winner => console.log(winner)); // "fast"

Test Your Knowledge

ES6 Features Quiz

5 questions
Question 1

What is the difference between let and const?

Question 2

What is the correct arrow function syntax for a single expression?

Question 3

What does the spread operator (...) do with arrays?

Question 4

How do you import a default export?

Question 5

What keyword is used to call a parent class constructor?

Coding Challenge

Refactor to ES6
Easy

Take the old ES5 code and refactor it using modern ES6+ features: let/const, arrow functions, template literals, destructuring, default parameters, and spread operator.

Starter Code
// Challenge: Refactor this ES5 code to modern ES6+
// Use: let/const, arrow functions, template literals,
// destructuring, default params, and spread operator

var users = [
  { name: "Alice", age: 25, role: "admin" },
  { name: "Bob", age: 30, role: "user" },
  { name: "Carol", age: 28, role: "user" }
];

// Refactor this function
function createGreeting(user) {
  var name = user.name;
  var role = user.role;
  return "Hello, " + name + "! You are a " + role + ".";
}

// Refactor this function
function filterByRole(users, role) {
  if (role === undefined) {
    role = "user";
  }
  return users.filter(function(user) {
    return user.role === role;
  });
}

// Refactor this function
function combineUsers(users1, users2) {
  var combined = [];
  for (var i = 0; i < users1.length; i++) {
    combined.push(users1[i]);
  }
  for (var j = 0; j < users2.length; j++) {
    combined.push(users2[j]);
  }
  return combined;
}

// Test
console.log(createGreeting(users[0]));
console.log(filterByRole(users));
console.log(combineUsers(users, [{ name: "Dave", age: 35, role: "admin" }]));

Summary

  • let/const - Block-scoped variables (use const by default)
  • Arrow functions - Shorter syntax, lexical this
  • Template literals - String interpolation with backticks
  • Destructuring - Extract values from objects/arrays
  • Spread/Rest - Expand or collect elements with ...
  • Default parameters - Fallback values for function args
  • Classes - Cleaner OOP syntax (still prototypes underneath)
  • Modules - Native import/export for code organization
  • Promises - Better async handling