Modern JavaScript - ES6 and Beyond
What is ES6?
ES6 (ECMAScript 2015) was a major update to JavaScript that introduced features still used daily by every professional developer. Subsequent yearly releases (ES2016, ES2017, ...) added more features. This lesson covers the most important modern features you will use constantly in real projects.
Destructuring
Destructuring was covered briefly in the Arrays and Objects lesson. Here we look at advanced patterns.
Array Destructuring with Skipping and Rest
const [first, , third] = [10, 20, 30]; // Skip index 1
console.log(first, third); // 10, 30
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
Object Destructuring with Renaming and Defaults
const config = { theme: "dark", lang: "en" };
const { theme: colorTheme, lang, fontSize = 16 } = config;
console.log(colorTheme); // "dark" — renamed from 'theme'
console.log(lang); // "en"
console.log(fontSize); // 16 — default value used
Destructuring in Function Parameters
function renderUser({ name, role = "Student", isActive }) {
return `${name} (${role}) — ${isActive ? "Active" : "Inactive"}`;
}
console.log(renderUser({ name: "Amara", isActive: true }));
// "Amara (Student) — Active"
Spread and Rest Operators
Both operators use the ... syntax but serve opposite purposes.
Spread — Expand an Iterable
// Spread into a new array
const base = [1, 2, 3];
const extended = [...base, 4, 5];
console.log(extended); // [1, 2, 3, 4, 5]
// Spread into a function call
const numbers = [5, 2, 8, 1, 9];
console.log(Math.max(...numbers)); // 9
// Spread to copy/merge objects
const defaults = { theme: "light", lang: "en" };
const userPrefs = { lang: "fr" };
const merged = { ...defaults, ...userPrefs };
console.log(merged); // { theme: "light", lang: "fr" }
Rest — Collect Remaining Values
// Rest in function parameters
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100
Optional Chaining (?.)
Optional chaining prevents TypeErrors when accessing properties on potentially null or undefined values:
const user = {
profile: {
address: null
}
};
// Without optional chaining — crashes
// const city = user.profile.address.city; // TypeError!
// With optional chaining — safe
const city = user?.profile?.address?.city;
console.log(city); // undefined — no error
// Works with method calls too
const length = user?.getName?.();
Nullish Coalescing (??)
The nullish coalescing operator returns the right-hand value only when the left side is null or undefined (unlike || which also triggers on 0, "", and false):
const count = 0;
console.log(count || 10); // 10 — wrong! 0 is falsy
console.log(count ?? 10); // 0 — correct! 0 is not null/undefined
const name = "";
console.log(name || "Guest"); // "Guest" — might not be desired
console.log(name ?? "Guest"); // "" — empty string is preserved
Array Methods: map, filter, reduce Revisited
These array methods combined with arrow functions and destructuring form the backbone of modern JavaScript data processing:
const students = [
{ name: "Amara", score: 88, passed: true },
{ name: "James", score: 45, passed: false },
{ name: "Fatima", score: 92, passed: true },
{ name: "Kwame", score: 55, passed: false }
];
// Get names of students who passed, sorted alphabetically
const passedNames = students
.filter(({ passed }) => passed)
.map(({ name }) => name)
.sort();
console.log(passedNames); // ["Amara", "Fatima"]
// Average score of all students
const average = students.reduce((sum, { score }) => sum + score, 0) / students.length;
console.log("Average:", average); // 70
Modules — import and export
JavaScript modules let you split code across files and import only what you need:
// utils.js — named exports
export function formatDate(date) {
return date.toLocaleDateString("en-GB");
}
export const MAX_RETRIES = 3;
// Default export (one per file)
export default function calculateTax(amount, rate = 0.2) {
return amount * rate;
}
// main.js — importing
import calculateTax, { formatDate, MAX_RETRIES } from "./utils.js";
console.log(calculateTax(100)); // 20
console.log(formatDate(new Date())); // e.g., "28/08/2026"
console.log(MAX_RETRIES); // 3
Key Takeaways
- Destructuring cleanly extracts values from arrays and objects, including renaming and default values
- Spread (...) expands iterables; rest (...) collects remaining values — both use the same syntax with opposite roles
- Optional chaining (?.) safely traverses nested properties without throwing if any link is null or undefined
- Nullish coalescing (??) provides a default only for null/undefined, unlike || which also triggers on 0 and ""
- Chaining .filter().map().reduce() on arrays is the idiomatic modern JavaScript approach to data transformation
- ES modules (import/export) allow code to be split across files; use named exports for utilities and default export for the main item
Practice Exercise
- Given an array of product objects with name, price, and inStock properties, use method chaining to get the names of all in-stock products with price above 20, sorted alphabetically
- Write a function
getFullName({ firstName, lastName, title = "Ms" })using parameter destructuring with a default - Write a
sumAll(...numbers)function using rest parameters and reduce - Demonstrate the difference between
||and??when the value is0
Try it yourself
Key Takeaways
- Destructuring in function parameters makes code more readable by naming what properties you need upfront
- Spread (...) expands iterables into individual values; rest (...) collects remaining values into an array
- Optional chaining (?.) safely accesses nested properties, returning undefined instead of throwing a TypeError
- Nullish coalescing (??) provides a default only for null/undefined — use it over || when 0 or false are valid values
- Chaining .filter().map().sort() on arrays creates expressive, readable data transformation pipelines
- ES modules use export/import to split code across files; default exports are the primary item, named exports are utilities
Quick Quiz
1.What is the difference between the spread (...) and rest (...) operators?
2.When should you use ?? instead of || for providing a default value?
3.What does the optional chaining operator (?.) return if a property in the chain is null?
4.What is the correct syntax to export a default function from a module?
Ready to go further?
CareerEx gives you structured 12-week training, live classes every Saturday and Sunday, real tutor feedback, and a certificate. Join the next cohort.
Join CareerEx