On 25 June 2025, the 129th Ecma General Assembly approved the ECMAScript 2025 language specification (press release), which means that it’s officially a standard now.
This blog post explains what’s new.
The editors of this release are:
Import attributes provide the syntactic foundation for importing non-JavaScript artifacts. The first such artifacts to be supported are JSON modules:
// Static import
import configData1 from './config-data.json' with { type: 'json' };
// Dynamic import
const configData2 = await import(
'./config-data.json', { with: { type: 'json' } }
);
The object literal syntax after with
is used for specifying import attributes. type
is an import attribute.
Iterator helper methods let us do more with iterators:
const arr = ['a', '', 'b', '', 'c', '', 'd', '', 'e'];
assert.deepEqual(
arr.values() // creates an iterator
.filter(x => x.length > 0)
.drop(1)
.take(3)
.map(x => `=${x}=`)
.toArray()
,
['=b=', '=c=', '=d=']
);
Some of the iterator helper methods work like the Array methods with the same names:
iterator.filter(filterFn)
iterator.map(mapFn)
iterator.flatMap(mapFn)
iterator.some(fn)
iterator.every(fn)
iterator.find(fn)
iterator.reduce(reducer, initialValue?)
iterator.forEach(fn)
Other iterator helper methods are unique to iterators:
iterator.drop(limit)
limit
elements of iterator
.iterator.take(limit)
limit
elements of iterator
.iterator.toArray()
iterator
in an Array and returns it.Set
and Map
.There are several new Set methods:
Set.prototype.intersection(other)
Set.prototype.union(other)
Set.prototype.difference(other)
Set.prototype.symmetricDifference(other)
Set.prototype.isSubsetOf(other)
Set.prototype.isSupersetOf(other)
Set.prototype.isDisjointFrom(other)
Examples:
assert.deepEqual(
new Set(['a', 'b', 'c']).union(new Set(['b', 'c', 'd'])),
new Set(['a', 'b', 'c', 'd'])
);
assert.deepEqual(
new Set(['a', 'b', 'c']).intersection(new Set(['b', 'c', 'd'])),
new Set(['b', 'c'])
);
assert.deepEqual(
new Set(['a', 'b']).isSubsetOf(new Set(['a', 'b', 'c'])),
true
);
assert.deepEqual(
new Set(['a', 'b', 'c']).isSupersetOf(new Set(['a', 'b'])),
true
);
RegExp.escape()
RegExp.escape()
escapes text so that it can be used inside a regular expression – e.g., the following code removes all occurrences of text
inside str
that are not quoted:
function removeUnquotedText(str, text) {
const regExp = new RegExp(
`(?<!“)${RegExp.escape(text)}(?!”)`,
'gu'
);
return str.replaceAll(regExp, '•');
}
assert.equal(
removeUnquotedText('“yes” and yes and “yes”', 'yes'),
'“yes” and • and “yes”'
);
Regular expression pattern modifiers (inline flags) let us apply flags to parts of a regular expression (vs. all of the regular expression) – for example, in the following regular expression, the flag i
is only applied to “HELLO”:
> /^x(?i:HELLO)x$/.test('xHELLOx')
true
> /^x(?i:HELLO)x$/.test('xhellox')
true
> /^x(?i:HELLO)x$/.test('XhelloX')
false
Duplicate named capture groups: We can now use the same group name twice – as long as it appears in different alternatives:
const RE = /(?<chars>a+)|(?<chars>b+)/v;
assert.deepEqual(
RE.exec('aaa').groups,
{
chars: 'aaa',
__proto__: null,
}
);
assert.deepEqual(
RE.exec('bb').groups,
{
chars: 'bb',
__proto__: null,
}
);
Promise.try()
Promise.try()
lets us start a Promise chain with code that is not purely asynchronous – e.g.:
function computeAsync() {
return Promise.try(() => {
const value = syncFuncMightThrow();
return asyncFunc(value);
});
}
This support provides the following features:
Math.f16round()
Float16Array
DataView.prototype.getFloat16()
DataView.prototype.setFloat16()
My book “Exploring JavaScript (ES2025 Edition)” is free to read online. Two chapters are especially relevant: