JavaScript ES7+ Features - Modern ECMAScript Guide
JavaScript ES7+ / Modern ECMAScript
After ES6, JavaScript moved to a yearly release cycle. Instead of waiting many years for one large language update, ECMAScript now receives smaller improvements almost every year. ES7+ usually means ES2016 and later: ES2016, ES2017, ES2018, ES2019, ES2020, ES2021, ES2022, ES2023, ES2024, ES2025, and future editions.
These releases added practical features that modern developers use constantly: async/await, optional chaining, nullish coalescing, BigInt, array copy methods, Object.groupBy(), new Set methods, iterator helpers, JSON modules, RegExp.escape(), and more.
ES7+ Feature Timeline
The table below gives a quick map of important ECMAScript features added after ES6.
| Edition | Year | Important Features |
|---|---|---|
| ES2016 / ES7 | 2016 | Array.includes(), exponentiation operator ** |
| ES2017 / ES8 | 2017 | async/await, Object.values(), Object.entries(), string padding |
| ES2018 / ES9 | 2018 | Object rest/spread, Promise.finally(), async iteration, RegExp improvements |
| ES2019 / ES10 | 2019 | flat(), flatMap(), Object.fromEntries(), optional catch binding |
| ES2020 / ES11 | 2020 | Optional chaining, nullish coalescing, BigInt, Promise.allSettled(), globalThis |
| ES2021 / ES12 | 2021 | replaceAll(), logical assignment, numeric separators, Promise.any() |
| ES2022 / ES13 | 2022 | at(), class fields, private fields, top-level await, Error.cause |
| ES2023 / ES14 | 2023 | Change-array-by-copy methods, findLast(), findLastIndex() |
| ES2024 / ES15 | 2024 | Object.groupBy(), Map.groupBy(), Promise.withResolvers(), Unicode string helpers |
| ES2025 / ES16 | 2025 | Iterator helpers, Set methods, JSON modules, import attributes, Promise.try(), RegExp.escape(), Float16Array |
Array.includes() and Exponentiation
ES2016 introduced two small but useful additions. Array.includes() checks whether an array contains a value. The exponentiation operator ** raises a number to a power and is easier to read than Math.pow().
const roles = ["admin", "editor", "viewer"];
console.log(roles.includes("editor")); // true
console.log(roles.includes("owner")); // false
console.log(2 ** 3); // 8
console.log(Math.pow(2, 3)); // 8
async and await
ES2017 added async and await, which make promise-based code read like synchronous code. An async function always returns a promise, and await pauses inside that function until the promise settles.
async function loadUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
loadUser(7)
.then(user => console.log(user.name))
.catch(error => console.error(error.message));
Object.values(), Object.entries(), and Object.fromEntries()
Object.values() returns an array of object values. Object.entries() returns key-value pairs. ES2019 added Object.fromEntries(), which converts key-value pairs back into an object.
const scores = {
Asha: 92,
Rohan: 78,
Meera: 88
};
console.log(Object.values(scores)); // [92, 78, 88]
console.log(Object.entries(scores)); // [["Asha", 92], ["Rohan", 78], ["Meera", 88]]
const passedEntries = Object.entries(scores)
.filter(([name, score]) => score >= 80);
const passed = Object.fromEntries(passedEntries);
console.log(passed); // { Asha: 92, Meera: 88 }
String Padding and replaceAll()
ES2017 added padStart() and padEnd() for formatting strings. ES2021 added replaceAll() for replacing every occurrence of a string pattern.
const invoiceNumber = "42";
console.log(invoiceNumber.padStart(5, "0")); // 00042
console.log("Total".padEnd(10, ".")); // Total.....
const slug = "learn javascript javascript".replaceAll(" ", "-");
console.log(slug); // learn-javascript-javascript
Object Rest and Spread
ES2018 brought rest/spread syntax to objects. Object rest collects remaining properties, while object spread copies or merges properties into a new object.
const user = {
id: 101,
name: "Nisha",
password: "secret",
role: "admin"
};
const { password, ...publicUser } = user;
console.log(publicUser); // { id: 101, name: "Nisha", role: "admin" }
const updatedUser = {
...publicUser,
role: "editor",
active: true
};
console.log(updatedUser);
Promise.finally(), allSettled(), any(), withResolvers(), and try()
Modern JavaScript added several promise helpers. finally() runs cleanup after success or failure. allSettled() waits for every promise. any() resolves when the first promise fulfills. withResolvers() creates a promise with exposed resolve and reject functions. Promise.try() wraps sync or async work in a promise.
const fast = Promise.resolve("fast result");
const slow = new Promise(resolve => setTimeout(() => resolve("slow result"), 1000));
const failed = Promise.reject(new Error("failed"));
Promise.allSettled([fast, slow, failed]).then(results => {
results.forEach(result => console.log(result.status));
});
Promise.any([failed, slow, fast])
.then(value => console.log(value))
.finally(() => console.log("cleanup"));
flat() and flatMap()
ES2019 added Array.prototype.flat() and flatMap(). Use flat() to flatten nested arrays and flatMap() when each item should produce zero, one, or many output items.
const nested = [1, [2, 3], [4, [5]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5]
const sentences = ["learn js", "write code"];
const words = sentences.flatMap(sentence => sentence.split(" "));
console.log(words); // ["learn", "js", "write", "code"]
Optional Chaining
Optional chaining ?. safely reads nested properties or calls functions when part of the chain may be null or undefined. If a value is missing, JavaScript returns undefined instead of throwing an error.
const user = {
name: "Ravi",
profile: {
social: {
twitter: "@ravi"
}
}
};
console.log(user.profile?.social?.twitter); // @ravi
console.log(user.settings?.theme); // undefined
user.notify?.("Welcome"); // calls only if notify exists
Nullish Coalescing
The nullish coalescing operator ?? provides a fallback only when the left side is null or undefined. It does not replace valid falsy values such as 0, false, or an empty string.
const settings = {
volume: 0,
darkMode: false
};
console.log(settings.volume ?? 50); // 0
console.log(settings.darkMode ?? true); // false
console.log(settings.language ?? "en"); // en
BigInt and Numeric Separators
BigInt represents integers larger than the safe Number limit. Numeric separators use underscores to make large numbers easier to read.
const safeNumber = Number.MAX_SAFE_INTEGER;
const largeNumber = 9_007_199_254_740_991n;
console.log(safeNumber);
console.log(largeNumber + 10n);
const price = 1_50_000;
console.log(price); // 150000
Logical Assignment Operators
ES2021 added logical assignment operators. They combine logical checks with assignment and are useful for setting defaults or updating values only under certain conditions.
const config = {
retries: 0,
title: ""
};
config.retries ??= 3; // keeps 0 because it is not null or undefined
config.title ||= "Untitled"; // replaces empty string because it is falsy
config.enabled &&= true; // assigns only if enabled is truthy
console.log(config);
Array at(), findLast(), and Copy Methods
at() supports positive and negative indexes. ES2023 added findLast() and findLastIndex(). It also added copy methods such as toSorted(), toReversed(), toSpliced(), and with(), which return new arrays instead of mutating the original.
const numbers = [4, 8, 15, 16, 23, 42];
console.log(numbers.at(-1)); // 42
console.log(numbers.findLast(number => number < 20)); // 16
const sorted = numbers.toSorted((a, b) => a - b);
const changed = numbers.with(0, 99);
console.log(numbers); // original array is unchanged
console.log(sorted);
console.log(changed);
Class Fields, Private Fields, and Error.cause
ES2022 improved classes with public fields, private fields, static blocks, and better error metadata. Private fields start with # and can only be accessed inside the class body.
class Counter {
#value = 0;
increment() {
this.#value++;
return this.#value;
}
get value() {
return this.#value;
}
}
const counter = new Counter();
console.log(counter.increment()); // 1
console.log(counter.value); // 1
Top-Level await and JSON Modules
Top-level await lets ES modules wait for async work without wrapping everything in an async function. JSON modules and import attributes make it possible to import JSON data as a module in supported environments.
// settings.json
// { "theme": "dark", "language": "en" }
import settings from "./settings.json" with { type: "json" };
const response = await fetch("/api/current-user");
const currentUser = await response.json();
console.log(settings.theme);
console.log(currentUser.name);
Object.groupBy() and Map.groupBy()
ES2024 added grouping helpers. Object.groupBy() groups values into a plain object. Map.groupBy() groups values into a Map, which is useful when group keys are not simple strings.
const tasks = [
{ title: "Write tutorial", status: "done" },
{ title: "Record video", status: "pending" },
{ title: "Publish page", status: "done" }
];
const grouped = Object.groupBy(tasks, task => task.status);
console.log(grouped.done);
console.log(grouped.pending);
New Set Methods
ES2025 added built-in set operations. These methods make mathematical set logic much easier to read than manual loops and filters.
const frontend = new Set(["html", "css", "javascript"]);
const backend = new Set(["node", "javascript", "sql"]);
console.log(frontend.union(backend));
console.log(frontend.intersection(backend));
console.log(frontend.difference(backend));
console.log(frontend.isDisjointFrom(backend)); // false
Iterator Helpers
ES2025 introduced iterator helpers such as map(), filter(), take(), drop(), and toArray() on iterators. Unlike array methods, iterator helpers are lazy: they process values as needed instead of creating intermediate arrays at every step.
const numbers = [1, 2, 3, 4, 5, 6].values();
const result = numbers
.filter(number => number % 2 === 0)
.map(number => number * 10)
.take(2)
.toArray();
console.log(result); // [20, 40]
RegExp.escape() and Modern Regular Expressions
RegExp.escape() safely escapes user-provided text before placing it inside a regular expression. This prevents special characters from accidentally changing the pattern.
const userSearch = "price (USD)?";
const safePattern = RegExp.escape(userSearch);
const regex = new RegExp(safePattern, "i");
console.log(regex.test("Price (USD)?")); // true
const name = user.profile.name;
const name = user.profile?.name;
const volume = settings.volume || 50;
const volume = settings.volume ?? 50;
array.sort();
const sorted = array.toSorted();
new RegExp(userInput)
new RegExp(RegExp.escape(userInput))
- ES7+ means all ECMAScript versions after ES6, starting from ES2016.
- async/await, optional chaining, nullish coalescing, BigInt, and modern array methods are everyday ES7+ features.
- Use copy array methods like toSorted() and toReversed() when mutation would create bugs.
- Object.groupBy(), Set methods, and iterator helpers make data transformation more expressive.
- Very new features may require modern browsers, recent Node.js versions, transpilers, or polyfills.
Frequently Asked Questions
Conclusion
ES7+ is not one single release. It is the steady evolution of JavaScript after ES6. The most important idea is to learn the features that improve real code: safer property access, clearer async handling, immutable array updates, better data grouping, stronger collection tools, and cleaner modules.
When you use newer ECMAScript features, always check your target environment. A feature may be standardized but still require a recent browser, Node.js version, transpiler, or polyfill in production.
Level Up Your Javascript Skills
Master Javascript with these hand-picked resources