ECMAScript 2025: The New JavaScript Features You Need to Know
Hello HaWkers, ECMAScript 2025 brought one of the most substantial updates in recent years to JavaScript. With new Iterator helpers, Set methods, direct JSON import, and Promise improvements, the language continues evolving to meet modern developers' needs.
Let's explore each of these features with practical examples you can start using today.
Iterator Helpers: The Big Star
The most anticipated addition of ES2025 are Iterator helpers. Finally, we can use methods like map, filter, and reduce directly on iterators, without needing to convert to arrays.
Why This Matters
Before, working with iterators required constant conversion:
// Before ES2025 - Inefficient for large sets
function* generateNumbers(limit) {
for (let i = 0; i < limit; i++) {
yield i;
}
}
// Had to convert to array first
const numbers = [...generateNumbers(1000000)];
const evens = numbers.filter(n => n % 2 === 0);
const doubled = evens.map(n => n * 2);
const sum = doubled.reduce((acc, n) => acc + n, 0);
// Problem: Creates 3 intermediate arrays in memoryNow with Iterator helpers:
// ES2025 - Lazy evaluation, no intermediate arrays
function* generateNumbers(limit) {
for (let i = 0; i < limit; i++) {
yield i;
}
}
const result = generateNumbers(1000000)
.filter(n => n % 2 === 0)
.map(n => n * 2)
.reduce((acc, n) => acc + n, 0);
// Processes item by item, without creating intermediate arrays
console.log(result);
Available Methods
The Iterator object now has native functional methods:
// map - Transform each element
const iterator = [1, 2, 3].values();
const doubled = iterator.map(x => x * 2);
console.log([...doubled]); // [2, 4, 6]
// filter - Filter elements
const numbers = [1, 2, 3, 4, 5].values();
const evens = numbers.filter(x => x % 2 === 0);
console.log([...evens]); // [2, 4]
// take - Get the first N elements
const infinite = function* () {
let i = 0;
while (true) yield i++;
}();
const firstFive = infinite.take(5);
console.log([...firstFive]); // [0, 1, 2, 3, 4]
// drop - Skip the first N elements
const list = [1, 2, 3, 4, 5].values();
const withoutFirst = list.drop(2);
console.log([...withoutFirst]); // [3, 4, 5]
// flatMap - Map + flatten
const nested = [[1, 2], [3, 4]].values();
const flattened = nested.flatMap(arr => arr.values());
console.log([...flattened]); // [1, 2, 3, 4]Real Use Case: Data Processing
// Processing lines from a large file with lazy evaluation
async function* readLines(file) {
const reader = file.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop(); // Keep incomplete line
for (const line of lines) {
yield line;
}
}
if (buffer) yield buffer;
}
// Using iterator helpers to process
const processedCsv = readLines(largeFile)
.filter(line => line.trim() !== '')
.filter(line => !line.startsWith('#'))
.map(line => line.split(','))
.filter(fields => fields.length === 4)
.map(([name, email, age, city]) => ({
name: name.trim(),
email: email.trim(),
age: parseInt(age),
city: city.trim()
}))
.filter(person => person.age >= 18);
// Only 100 records, without loading entire file
const first100 = processedCsv.take(100);
New Set Methods
JavaScript Sets finally received methods that have existed in other languages for decades.
Set Operations
const setA = new Set([1, 2, 3, 4, 5]);
const setB = new Set([4, 5, 6, 7, 8]);
// union - All elements from both sets
const union = setA.union(setB);
console.log([...union]); // [1, 2, 3, 4, 5, 6, 7, 8]
// intersection - Common elements
const intersection = setA.intersection(setB);
console.log([...intersection]); // [4, 5]
// difference - Elements in A that are not in B
const difference = setA.difference(setB);
console.log([...difference]); // [1, 2, 3]
// symmetricDifference - Elements exclusive to each set
const symmetricDiff = setA.symmetricDifference(setB);
console.log([...symmetricDiff]); // [1, 2, 3, 6, 7, 8]
// isSubsetOf - Check if A is contained in B
const subset = new Set([4, 5]);
console.log(subset.isSubsetOf(setA)); // true
console.log(subset.isSubsetOf(setB)); // true
// isSupersetOf - Check if A contains B
console.log(setA.isSupersetOf(subset)); // true
// isDisjointFrom - Check if no common elements
const setC = new Set([10, 11, 12]);
console.log(setA.isDisjointFrom(setC)); // true
console.log(setA.isDisjointFrom(setB)); // falsePractical Application: Permissions System
class PermissionsSystem {
constructor() {
this.roles = new Map();
}
defineRole(name, permissions) {
this.roles.set(name, new Set(permissions));
}
userPermissions(userRoles) {
return userRoles.reduce((acc, role) => {
const rolePermissions = this.roles.get(role) || new Set();
return acc.union(rolePermissions);
}, new Set());
}
checkAccess(userRoles, requiredPermissions) {
const userPerms = this.userPermissions(userRoles);
const required = new Set(requiredPermissions);
// Check if user has all required permissions
return required.isSubsetOf(userPerms);
}
missingPermissions(userRoles, requiredPermissions) {
const userPerms = this.userPermissions(userRoles);
const required = new Set(requiredPermissions);
// Return permissions user doesn't have
return required.difference(userPerms);
}
}
// Usage
const system = new PermissionsSystem();
system.defineRole('admin', ['create', 'read', 'update', 'delete', 'manage_users']);
system.defineRole('editor', ['create', 'read', 'update']);
system.defineRole('reader', ['read']);
const user = ['editor', 'reader'];
const requiredPermissions = ['create', 'delete'];
console.log(system.checkAccess(user, requiredPermissions)); // false
console.log([...system.missingPermissions(user, requiredPermissions)]); // ['delete']
Import JSON Directly
Now we can import JSON files directly as ES modules, without needing fetch or require.
// config.json
// {
// "apiUrl": "https://api.example.com",
// "timeout": 5000,
// "maxRetries": 3
// }
// Before - Needed fetch or fs
// const config = await fetch('./config.json').then(r => r.json());
// ES2025 - Direct import with assertion
import config from './config.json' with { type: 'json' };
console.log(config.apiUrl); // https://api.example.com
console.log(config.timeout); // 5000Use Cases
// Import static data
import translations from './lang/en-US.json' with { type: 'json' };
import routes from './routes.json' with { type: 'json' };
import schema from './validation-schema.json' with { type: 'json' };
// Dynamic import also works
const locale = 'en-US';
const messages = await import(`./lang/${locale}.json`, {
with: { type: 'json' }
});Promise.try: Simplifying Promise Chains
The new Promise.try method allows starting a Promise chain more cleanly, handling both synchronous and asynchronous functions.
// Before - Needed workarounds
function processData(data) {
// Can throw synchronous exception
const validated = validateData(data);
// Can return Promise
return saveToDatabase(validated);
}
// Old workaround
Promise.resolve()
.then(() => processData(data))
.then(result => console.log(result))
.catch(error => console.error(error));
// ES2025 - Cleaner
Promise.try(() => processData(data))
.then(result => console.log(result))
.catch(error => console.error(error));Why Promise.try Is Useful
// Function that can be sync or async
function fetchUser(id) {
// Sync validation can throw error
if (!id || typeof id !== 'number') {
throw new Error('Invalid ID');
}
// Sync cache
if (cache.has(id)) {
return cache.get(id); // Sync return
}
// Async fetch
return fetch(`/api/users/${id}`).then(r => r.json());
}
// Promise.try handles both cases uniformly
Promise.try(() => fetchUser(userId))
.then(user => render(user))
.catch(error => showError(error));
// Equivalent to:
// new Promise(resolve => resolve(fetchUser(userId)))
// .then(...)
// .catch(...);
Float16Array: New Typed Array
For machine learning applications and data processing that need memory efficiency, the new Float16Array offers 16-bit floating point numbers.
// Float16Array uses half the memory of Float32Array
const data16 = new Float16Array([1.5, 2.5, 3.5, 4.5]);
const data32 = new Float32Array([1.5, 2.5, 3.5, 4.5]);
console.log(data16.byteLength); // 8 bytes
console.log(data32.byteLength); // 16 bytes
// Useful for ML where full precision isn't needed
function createEfficientTensor(dimensions, values) {
const total = dimensions.reduce((a, b) => a * b, 1);
const data = new Float16Array(total);
for (let i = 0; i < values.length; i++) {
data[i] = values[i];
}
return {
shape: dimensions,
data: data,
dtype: 'float16'
};
}
const tensor = createEfficientTensor([2, 3], [1, 2, 3, 4, 5, 6]);Regular Expression Improvements
ES2025 also brought improvements to regular expressions, including the inline flag modifier.
// Inline flag modifier - Enables/disables flags in parts of regex
const regex = /(?i:hello) world/;
// (?i:...) makes only "hello" case-insensitive
console.log(regex.test('HELLO world')); // true
console.log(regex.test('hello WORLD')); // false (world needs to be lowercase)
// Useful for complex patterns
const emailRegex = /(?i:[a-z0-9._%+-]+)@(?i:[a-z0-9.-]+)\.(?i:[a-z]{2,})/;
Browser Support
Most ES2025 features are already available in modern browsers:
Iterator Helpers:
- Chrome 122+
- Firefox 131+
- Safari 17.4+
Set Methods:
- Chrome 122+
- Firefox 127+
- Safari 17+
JSON Modules:
- Chrome 123+
- Firefox 135+
- Safari 17.2+
Promise.try:
- Chrome 128+
- Firefox 132+
- Safari 18+
For projects needing to support older browsers, use transpilers like Babel with appropriate plugins.
Migrating Your Code
Here's a checklist to start using the new features:
1. Update your tools:
npm update typescript @babel/core @babel/preset-env2. Configure TypeScript target:
{
"compilerOptions": {
"target": "ES2025",
"lib": ["ES2025", "DOM"]
}
}3. Add polyfills if needed:
npm install core-js@latest// Import only necessary polyfills
import 'core-js/actual/iterator';
import 'core-js/actual/set';
import 'core-js/actual/promise/try';ECMAScript 2025 represents a significant step in JavaScript's evolution, bringing features that make code more expressive and efficient. If you want to deepen your knowledge in modern JavaScript, I recommend checking out the article on Web Workers: Performance with Threads where you'll learn advanced optimization techniques.

