El objeto Set lleva en JavaScript desde ES2015 y es muy útil para guardar valores únicos sin duplicados. Lo que nunca tuvo son métodos para hacer operaciones de teoría de conjuntos: unión, intersección, diferencia... lo básico que cualquier lenguaje con conjuntos debería ofrecer.
Si querías la unión de dos Sets, lo hacías así:
const union = new Set([...setA, ...setB]);
Para la intersección, peor todavía:
const intersection = new Set([...setA].filter(x => setB.has(x)));
Funciona, pero es feo de leer y te obliga a convertir el Set en array, filtrar, y volver a crear un Set. Para la diferencia, más de lo mismo:
const difference = new Set([...setA].filter(x => !setB.has(x)));
Con ES2025 esto ya no hace falta. Hay siete métodos nuevos en el prototipo de Set que cubren todas las operaciones habituales de conjuntos, y ya están disponibles de forma nativa en todos los navegadores y entornos modernos sin necesidad de ningún polyfill.
Los siete métodos nuevos
Aquí tienes el listado completo. Todos reciben otro conjunto como argumento y devuelven un nuevo Set sin modificar el original.
.union(other)
Devuelve un Set con todos los elementos que están en A, en B, o en ambos. Es la unión clásica.
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);
a.union(b); // Set {1, 2, 3, 4, 5}
.intersection(other)
Devuelve solo los elementos que están en A y también en B.
a.intersection(b); // Set {3}
.difference(other)
Devuelve los elementos que están en A pero no están en B. Ojo al orden: a.difference(b) no es lo mismo que b.difference(a).
a.difference(b); // Set {1, 2}
b.difference(a); // Set {4, 5}
.symmetricDifference(other)
Devuelve los elementos que están en A o en B, pero no en los dos a la vez. Es la diferencia simétrica, lo contrario de la intersección.
a.symmetricDifference(b); // Set {1, 2, 4, 5}
.isSubsetOf(other)
Devuelve true si todos los elementos de A están también en B.
const c = new Set([1, 2]);
c.isSubsetOf(a); // true
a.isSubsetOf(c); // false
.isSupersetOf(other)
El inverso: devuelve true si todos los elementos de B están en A.
a.isSupersetOf(c); // true
.isDisjointFrom(other)
Devuelve true si A y B no tienen ningún elemento en común.
const d = new Set([10, 20]);
a.isDisjointFrom(d); // true
a.isDisjointFrom(b); // false (comparten el 3)
Ejemplos prácticos
Los ejemplos de arriba son claros, pero los conjuntos abstractos de números no siempre ayudan a ver cuándo usar cada método. Aquí van algunos casos reales.
Tags comunes entre dos artículos
Tienes dos artículos y quieres saber qué tags comparten:
const tagsArticuloA = new Set(['javascript', 'async', 'promises', 'es2025']);
const tagsArticuloB = new Set(['javascript', 'typescript', 'es2025', 'types']);
const tagsComunes = tagsArticuloA.intersection(tagsArticuloB);
// Set {'javascript', 'es2025'}
Usuarios que se han dado de baja
Si tienes el conjunto de usuarios activos el mes pasado y el de este mes, la diferencia te da los que se fueron:
const usuariosMesAnterior = new Set([101, 102, 103, 104, 105]);
const usuariosMesActual = new Set([101, 103, 105, 106]);
const bajas = usuariosMesAnterior.difference(usuariosMesActual);
// Set {102, 104}
Permisos que sobran
Un usuario tiene ciertos permisos y un recurso requiere otros. Con difference ves qué permisos tiene el usuario que no necesita para ese recurso:
const permisosUsuario = new Set(['read', 'write', 'delete', 'admin']);
const permisosRequeridos = new Set(['read', 'write']);
const permisosInnecesarios = permisosUsuario.difference(permisosRequeridos);
// Set {'delete', 'admin'}
Y con isSubsetOf puedes comprobar si el usuario tiene todos los permisos que necesita:
permisosRequeridos.isSubsetOf(permisosUsuario); // true ? acceso permitido
Combinar IDs sin duplicados
Tienes dos fuentes de IDs de productos y quieres la lista completa sin repetidos:
const idsAlmacenA = new Set([1, 2, 3, 4]);
const idsAlmacenB = new Set([3, 4, 5, 6]);
const todosLosIds = idsAlmacenA.union(idsAlmacenB);
// Set {1, 2, 3, 4, 5, 6}
Los métodos son inmutables y encadenables
Ninguno de los siete métodos modifica el Set original. Siempre devuelven un Set nuevo, lo que facilita encadenarlos:
const resultado = setA.union(setB).difference(setC);
El orden de los elementos en el Set resultante sigue el orden de inserción, igual que en un Set normal. No hay sorpresas.
Aceptan cualquier iterable, no solo Sets
Esto es un detalle que marca la diferencia con otros lenguajes. El argumento no tiene por qué ser otro Set: puede ser un array, el resultado de Map.keys(), un generador, o cualquier cosa iterable.
const setA = new Set([1, 2, 3]);
setA.union([3, 4, 5]); // funciona con array
setA.intersection(new Map([[1, 'uno'], [2, 'dos']]).keys()); // funciona con Map.keys()
En Python, por ejemplo, los métodos de sets solo aceptan otros sets en ambos lados. JavaScript aquí es más flexible.
Compatibilidad en 2026
Estos métodos llevan disponibles en los navegadores principales desde 2024 y están marcados como Baseline 2025, lo que significa que ya funcionan en todos los entornos modernos:
- Chrome 122 y posterior
- Firefox 127 y posterior
- Safari 17 y posterior
- Node.js 22 y posterior
Si tienes que dar soporte a entornos más antiguos, core-js tiene polyfill para todos estos métodos. Pero si tu proyecto tiene como mínimo los navegadores de los últimos dos años, los tienes de forma nativa.
¿Qué pasa con lodash?
lodash tiene _.union, _.intersection y _.difference, pero trabajan con arrays, no con Sets. Si tu código ya usa Set, los nuevos métodos nativos son más directos y más eficientes: no crean arrays intermedios, así que el coste es O(n) en lugar de tener que convertir entre estructuras.
Si usas lodash solo para estas operaciones y ya tienes Sets en tu código, ahora puedes eliminar esa dependencia sin perder nada. Si usas lodash para otras cosas (como _.groupBy, _.debounce o _.cloneDeep), lo sigues necesitando para eso, pero para las operaciones de conjuntos ya no depende de él.
Más sobre estructuras de datos nativas en JavaScript en JavaScript moderno: estructuras de datos nativas, y si usas TypeScript junto a estas APIs, echa un vistazo a TypeScript y las nuevas APIs de JavaScript.
Imagen: Pexels / Digital Buggu
