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:
// 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:
// 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 varArrow Functions
A shorter syntax for writing functions:
// 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:
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:
// 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 1Spread and Rest Operators
The ... operator for expanding or collecting elements:
// 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:
// 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:
// 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)); // trueModules
Native import/export for organizing code:
// 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';Object Shorthand
Cleaner object literal syntax:
// 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:
// 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 questionsWhat is the difference between let and const?
What is the correct arrow function syntax for a single expression?
What does the spread operator (...) do with arrays?
How do you import a default export?
What keyword is used to call a parent class constructor?
Coding Challenge
Take the old ES5 code and refactor it using modern ES6+ features: let/const, arrow functions, template literals, destructuring, default parameters, and spread operator.
// 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