Modern JavaScript Features
JavaScript gets a new edition every year. If you learned it a while ago — or you're reading older tutorials and Stack Overflow answers — this lesson maps out what changed, from the huge ES2015 update to the features added in the last couple of years, so you can recognise and use modern syntax.
ES2015 (ES6): the big one
ES2015 transformed the language. Nearly everything in this course relies on it:
| Feature | Lesson |
|---|---|
let and const | 05 |
| Arrow functions | 23 |
| Template literals | 15 |
| Default and rest parameters, spread, destructuring | 24, 33 |
| Classes | 39–40 |
Modules (import/export) | 55 |
| Promises | 52 |
Map, Set, iterators, generators, for…of, symbols | 12, 34, 35 |
2016–2020
JS es2016-2020.js
// ES2016: exponent operator, Array.prototype.includes console.log(2 ** 10, [1, 2, 3].includes(2)); // ES2017: Object.values/entries, string padding (async/await too) console.log(Object.entries({ a: 1 }), "5".padStart(3, "0")); // ES2018: object spread/rest, Promise.finally, named regex groups const { a, ...rest } = { a: 1, b: 2, c: 3 }; console.log(rest, "2026-10".match(/(?<year>\d{4})/).groups.year); // ES2019: flat, flatMap, Object.fromEntries, optional catch binding console.log([[1], [2, [3]]].flat(2), Object.fromEntries([["k", "v"]])); // ES2020: optional chaining, nullish coalescing, BigInt const config = { retries: 0 }; console.log(config.server?.port, config.retries ?? 3, 2n ** 64n);
Output
1024 true
[ [ 'a', 1 ] ] 005
{ b: 2, c: 3 } 2026
[ 1, 2, 3 ] { k: 'v' }
undefined 0 18446744073709551616n2021–2023
JS es2021-2023.js
// ES2021: replaceAll, logical assignment, numeric separators let title = "a-b-c".replaceAll("-", " "); let count; count ??= 1_000_000; console.log(title, count); // ES2022: .at(), Object.hasOwn, class fields & #private, top-level await, error cause console.log([10, 20, 30].at(-1), Object.hasOwn({ x: 1 }, "x")); class Account { #balance = 0; static currency = "EUR"; get balance() { return this.#balance; } } console.log(new Account().balance, Account.currency); // ES2023: findLast, and change-by-copy array methods const nums = [3, 1, 2]; console.log(nums.findLast(n => n > 1), nums.toSorted(), nums.with(0, 9), nums);
Output
a b c 1000000 30 true 0 EUR 2 [ 1, 2, 3 ] [ 9, 1, 2 ] [ 3, 1, 2 ]
2024–2025
JS es2024-2025.js
// ES2024: Object.groupBy / Map.groupBy, Promise.withResolvers, well-formed strings const pets = [{ n: "Rex", t: "dog" }, { n: "Tom", t: "cat" }, { n: "Fido", t: "dog" }]; console.log(Object.groupBy(pets, p => p.t).dog.length); const { promise, resolve } = Promise.withResolvers(); promise.then(v => console.log("resolved later with", v)); resolve("✓"); // ES2025: Set methods, iterator helpers, RegExp.escape, Promise.try const a = new Set([1, 2, 3]); console.log([...a.intersection(new Set([2, 3, 4]))]); console.log([1, 2, 3, 4].values().filter(n => n % 2 === 0).map(n => n * 10).toArray());
Output
2 [ 2, 3 ] [ 20, 40 ] resolved later with ✓
Arriving now
- Temporal — a modern, time-zone-aware replacement for
Date(lesson 20), shipping in browsers. - Explicit resource management —
usingdeclarations that clean up resources automatically at the end of a block. - Import attributes —
import data from "./data.json" with { type: "json" }. Array.fromAsync— collects an async iterable into an array.
To check whether a feature works in the browsers you support, look it up on caniuse.com or the browser-compatibility tables in MDN Web Docs.
Old patterns and their modern replacements
| You might see… | Modern equivalent |
|---|---|
var self = this; | Arrow functions |
arr.indexOf(x) !== -1 | arr.includes(x) |
a && a.b && a.b.c | a?.b?.c |
x !== undefined && x !== null ? x : d | x ?? d |
Object.assign({}, a, b) | { ...a, ...b } |
arr[arr.length - 1] | arr.at(-1) |
JSON.parse(JSON.stringify(obj)) | structuredClone(obj) |
Array.prototype.slice.call(arguments) | Rest parameters ...args |
| Callback pyramids | async/await |
jQuery $(…) for basic DOM work | querySelector, classList, fetch |