ECMAScript 2025: Los Nuevos Recursos de JavaScript que Necesitas Conocer
Hola HaWkers, el ECMAScript 2025 fue oficialmente aprobado y trae una serie de recursos que van a facilitar la vida de desarrolladores JavaScript. Desde mejoras en expresiones regulares hasta nuevos tipos de array para gráficos y machine learning, esta actualización tiene algo para todos.
¿Ya te preguntaste cómo JavaScript continúa evolucionando año tras año? Vamos a explorar cada nuevo recurso del ES2025 con ejemplos prácticos que puedes comenzar a usar hoy.
Visión General de las Novedades
Antes de sumergirnos en los detalles, aquí está un resumen de lo que el ECMAScript 2025 trae:
Principales adiciones:
- Promise.try() - Ejecución segura de funciones síncronas
- Float16Array - Nuevo TypedArray de media precisión
- Duplicate Named Capture Groups - Regex más flexible
- RegExp.escape() - Escape automático de caracteres especiales
- Set methods - Operaciones de conjunto nativas
- Iterator helpers - Métodos auxiliares para iteradores
💡 Contexto: JavaScript recibe actualizaciones anuales desde 2015 (ES6), manteniendo el lenguaje moderno y competitivo.
Promise.try(): Tratamiento Uniforme de Funciones
Uno de los recursos más prácticos del ES2025 es el Promise.try(), que resuelve un problema común: ejecutar funciones que pueden ser síncronas o asíncronas.
El Problema Antiguo
Antes, si tenías una función que podía lanzar error síncronamente, necesitabas tratamiento especial:
// Problema: si getUser lanza error síncrono, el catch no lo captura
function fetchUserData(userId) {
// Si userId es inválido, esto lanza error ANTES de la Promise
const user = getUser(userId); // ¡Puede lanzar error síncrono!
return Promise.resolve(user)
.then(user => processUser(user))
.catch(err => handleError(err)); // ¡No captura errores síncronos!
}
// Solución antigua: envolver en try-catch o Promise
function fetchUserDataSafe(userId) {
return new Promise((resolve, reject) => {
try {
const user = getUser(userId);
resolve(user);
} catch (err) {
reject(err);
}
}).then(user => processUser(user))
.catch(err => handleError(err));
}La Solución con Promise.try()
Ahora, todo queda más simple:
// ES2025: Promise.try resuelve el problema elegantemente
function fetchUserData(userId) {
return Promise.try(() => getUser(userId))
.then(user => processUser(user))
.catch(err => handleError(err));
}
// Funciona con funciones async también
function fetchUserDataAsync(userId) {
return Promise.try(async () => {
const user = await getUser(userId);
const profile = await getProfile(user.id);
return { user, profile };
})
.then(data => processData(data))
.catch(err => handleError(err));
}
// Ejemplo práctico: validación y fetch
function loadResource(resourceId) {
return Promise.try(() => {
// Validación síncrona que puede lanzar error
if (!isValidId(resourceId)) {
throw new Error('ID inválido');
}
// Operación asíncrona
return fetch(`/api/resources/${resourceId}`);
})
.then(response => response.json())
.catch(err => {
console.error('Error al cargar recurso:', err);
return null;
});
}
Float16Array: Precisión para Gráficos y ML
El nuevo Float16Array añade soporte para números de punto flotante de 16 bits, esencial para gráficos y machine learning.
Por Qué 16 Bits
Comparación de precisión:
| Tipo | Bits | Memoria | Uso |
|---|---|---|---|
| Float16 | 16 | 2 bytes | Gráficos, ML |
| Float32 | 32 | 4 bytes | Uso general |
| Float64 | 64 | 8 bytes | Alta precisión |
Usando Float16Array
// Creando un Float16Array
const halfFloats = new Float16Array(4);
halfFloats[0] = 1.5;
halfFloats[1] = 2.25;
halfFloats[2] = 0.125;
halfFloats[3] = -3.75;
console.log(halfFloats); // Float16Array(4) [1.5, 2.25, 0.125, -3.75]
// Creando a partir de array existente
const values = [0.5, 1.0, 1.5, 2.0, 2.5];
const f16 = Float16Array.from(values);
// Útil para WebGL y WebGPU
const vertexData = new Float16Array([
// x, y, z, u, v
-1.0, -1.0, 0.0, 0.0, 0.0,
1.0, -1.0, 0.0, 1.0, 0.0,
0.0, 1.0, 0.0, 0.5, 1.0,
]);
// Ahorro de memoria para ML
const weights = new Float16Array(1000000); // 2MB vs 4MB con Float32Funciones Auxiliares
// Nuevas funciones Math para Float16
const f16Value = Math.f16round(3.14159); // Redondea para precisión f16
console.log(f16Value); // 3.140625
// Útil para shaders y GPU computing
function prepareGPUData(floatArray) {
// Convierte Float32 para Float16 para enviar a GPU
const f16Data = Float16Array.from(floatArray);
return f16Data.buffer;
}
// DataView también soporta Float16
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setFloat16(0, 1.5); // Escribe Float16
view.setFloat16(2, 2.5, true); // Little-endian
const value1 = view.getFloat16(0); // Lee Float16
const value2 = view.getFloat16(2, true);
Duplicate Named Capture Groups
Una limitación frustrante de regex fue resuelta: ahora puedes usar el mismo nombre de grupo en diferentes partes de una expresión regular.
El Problema Antiguo
// Antes: esto era un error de sintaxis
// const dateRegex = /(?<day>\d{2})-(?<month>\d{2})|(?<month>\d{2})\/(?<day>\d{2})/;
// SyntaxError: Duplicate capture group name
// Solución antigua: nombres diferentes
const dateRegexOld = /(?<day1>\d{2})-(?<month1>\d{2})|(?<month2>\d{2})\/(?<day2>\d{2})/;
const match = '25-12'.match(dateRegexOld);
// Necesitaba verificar cuál grupo hizo match
const day = match.groups.day1 || match.groups.day2;
const month = match.groups.month1 || match.groups.month2;La Solución ES2025
// ES2025: mismo nombre en alternativas diferentes
const dateRegex = /(?<day>\d{2})-(?<month>\d{2})|(?<month>\d{2})\/(?<day>\d{2})/;
// Formato DD-MM
const match1 = '25-12'.match(dateRegex);
console.log(match1.groups.day); // "25"
console.log(match1.groups.month); // "12"
// Formato MM/DD
const match2 = '12/25'.match(dateRegex);
console.log(match2.groups.day); // "25"
console.log(match2.groups.month); // "12"
// Ejemplo más complejo: múltiples formatos de fecha
const flexibleDate = /
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})|
(?<day>\d{2})\/(?<month>\d{2})\/(?<year>\d{4})|
(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})
/x;
// Todos funcionan con los mismos nombres de grupo
['2025-12-25', '25/12/2025', '12-25-2025'].forEach(date => {
const m = date.match(flexibleDate);
console.log(`${m.groups.year}-${m.groups.month}-${m.groups.day}`);
});
RegExp.escape(): Escape Automático
Finalmente tenemos una forma nativa de escapar strings para uso en expresiones regulares.
El Problema
// Antes: necesitaba crear función propia o usar biblioteca
function escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
// O arriesgar bugs
const userInput = 'file.txt';
const regex = new RegExp(userInput); // Problema: . coincide cualquier carácter!
'fileAtxt'.match(regex); // ¡Match indeseado!La Solución Nativa
// ES2025: RegExp.escape()
const userInput = 'file.txt';
const escaped = RegExp.escape(userInput);
console.log(escaped); // "file\\.txt"
const regex = new RegExp(escaped);
'file.txt'.match(regex); // Match correcto
'fileAtxt'.match(regex); // null - ya no coincide
// Útil para búsqueda de texto literal
function findExactText(text, searchTerm) {
const escaped = RegExp.escape(searchTerm);
const regex = new RegExp(escaped, 'gi');
return text.match(regex);
}
// Funciona con cualquier carácter especial
const specialChars = '(hello) [world] {test} $100 ^start end$';
const safeRegex = new RegExp(RegExp.escape(specialChars));
// Ejemplo práctico: highlight de texto
function highlightText(content, searchTerm) {
const escaped = RegExp.escape(searchTerm);
const regex = new RegExp(`(${escaped})`, 'gi');
return content.replace(regex, '<mark>$1</mark>');
}
highlightText('Precio: $99.99', '$99.99');
// "Precio: <mark>$99.99</mark>"
Set Methods: Operaciones de Conjunto Nativas
El ES2025 añade métodos nativos para operaciones comunes de conjuntos.
Nuevos Métodos
const setA = new Set([1, 2, 3, 4, 5]);
const setB = new Set([4, 5, 6, 7, 8]);
// Unión: elementos en A O B
const union = setA.union(setB);
console.log([...union]); // [1, 2, 3, 4, 5, 6, 7, 8]
// Intersección: elementos en A Y B
const intersection = setA.intersection(setB);
console.log([...intersection]); // [4, 5]
// Diferencia: elementos en A pero no en B
const difference = setA.difference(setB);
console.log([...difference]); // [1, 2, 3]
// Diferencia simétrica: elementos en A o B, pero no ambos
const symmetricDiff = setA.symmetricDifference(setB);
console.log([...symmetricDiff]); // [1, 2, 3, 6, 7, 8]
// Subconjunto: ¿A está contenido en B?
const small = new Set([4, 5]);
console.log(small.isSubsetOf(setA)); // true
console.log(small.isSubsetOf(setB)); // true
// Superconjunto: ¿A contiene B?
console.log(setA.isSupersetOf(small)); // true
// Disjunto: ¿A y B no tienen elementos en común?
const setC = new Set([10, 11, 12]);
console.log(setA.isDisjointFrom(setC)); // true
console.log(setA.isDisjointFrom(setB)); // falseEjemplos Prácticos
// Gerenciamiento de permisos
const userPermissions = new Set(['read', 'write', 'delete']);
const requiredPermissions = new Set(['read', 'write']);
const hasAccess = requiredPermissions.isSubsetOf(userPermissions);
console.log(hasAccess); // true
// Encontrar tags en común entre posts
const post1Tags = new Set(['javascript', 'web', 'frontend']);
const post2Tags = new Set(['javascript', 'nodejs', 'backend']);
const commonTags = post1Tags.intersection(post2Tags);
console.log([...commonTags]); // ['javascript']
// Combinar listas de usuarios sin duplicatas
const team1 = new Set(['alice', 'bob', 'charlie']);
const team2 = new Set(['bob', 'diana', 'eve']);
const allMembers = team1.union(team2);
console.log([...allMembers]); // ['alice', 'bob', 'charlie', 'diana', 'eve']
Iterator Helpers: Métodos para Iteradores
Ahora iteradores tienen métodos auxiliares similares a los de arrays.
Métodos Disponibles
// Creando un iterador
function* infiniteNumbers() {
let n = 0;
while (true) {
yield n++;
}
}
// take(): obtener N primeros elementos
const first5 = infiniteNumbers().take(5);
console.log([...first5]); // [0, 1, 2, 3, 4]
// drop(): saltar N primeros elementos
const skip3take5 = infiniteNumbers().drop(3).take(5);
console.log([...skip3take5]); // [3, 4, 5, 6, 7]
// map(): transformar elementos
const doubled = infiniteNumbers()
.take(5)
.map(n => n * 2);
console.log([...doubled]); // [0, 2, 4, 6, 8]
// filter(): filtrar elementos
const evens = infiniteNumbers()
.take(10)
.filter(n => n % 2 === 0);
console.log([...evens]); // [0, 2, 4, 6, 8]
// flatMap(): map + flatten
function* pairs(n) {
yield n;
yield n * 10;
}
const flattened = [1, 2, 3].values()
.flatMap(n => pairs(n));
console.log([...flattened]); // [1, 10, 2, 20, 3, 30]Encadenamiento Fluido
// Combinando métodos
const result = infiniteNumbers()
.drop(10) // Salta los 10 primeros
.filter(n => n % 3 === 0) // Apenas múltiplos de 3
.map(n => n ** 2) // Eleva al cuadrado
.take(5); // Obtiene 5 resultados
console.log([...result]); // [144, 225, 324, 441, 576]
// Ejemplo práctico: procesamiento de datos
function* readLines(text) {
for (const line of text.split('\n')) {
yield line;
}
}
const logData = `
2025-01-01 ERROR: Connection failed
2025-01-01 INFO: Server started
2025-01-02 ERROR: Timeout
2025-01-02 INFO: Request processed
2025-01-03 ERROR: Invalid input
`;
const errors = readLines(logData)
.filter(line => line.includes('ERROR'))
.map(line => line.split('ERROR:')[1]?.trim())
.filter(msg => msg);
console.log([...errors]);
// ['Connection failed', 'Timeout', 'Invalid input']
Compatibilidad y Soporte
Antes de usar estos recursos en producción, verifica el soporte:
Status de Implementación
| Recurso | Chrome | Firefox | Safari | Node.js |
|---|---|---|---|---|
| Promise.try | 128+ | 132+ | 18.2+ | 22+ |
| Float16Array | 128+ | En dev | 18.2+ | 22+ |
| Duplicate Groups | 125+ | 129+ | 18+ | 21+ |
| RegExp.escape | 130+ | 134+ | En dev | 23+ |
| Set methods | 122+ | 127+ | 17+ | 22+ |
| Iterator helpers | 122+ | 131+ | 17+ | 22+ |
Polyfills y Transpilación
// Para ambientes que no soportan, usa core-js
import 'core-js/actual/promise/try';
import 'core-js/actual/set';
import 'core-js/actual/iterator';
// O configura babel con preset-env
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
targets: '> 0.25%, not dead',
useBuiltIns: 'usage',
corejs: 3
}]
]
};
Conclusión
El ECMAScript 2025 trae mejoras prácticas que resuelven problemas reales del día a día. Promise.try() simplifica tratamiento de errores, Float16Array abre puertas para gráficos y ML, y los nuevos métodos de Set e Iterator tornan operaciones comunes más elegantes.
JavaScript continúa evolucionando de forma consistente, añadiendo recursos que antes exigían bibliotecas externas o código boilerplate. Mantenerse actualizado con estas novedades es esencial para escribir código más limpio y eficiente.
Si quieres profundizarte en JavaScript moderno, recomiendo que revises otro artículo: Bun 1.2: El Runtime JavaScript Que Está Rompiendo Récords donde vas a descubrir cómo dominar programación asíncrona.

