En esta página
Patrones modernos de JavaScript
Destructuring avanzado
Ya vimos destructuring básico. Ahora exploramos patrones avanzados:
Destructuring anidado con defaults
const { a: { b = 'default' } = {} } = respuesta;El = {} previene errores si a es undefined.
Destructuring en parametros
Es un patrón muy comun para funciones con muchos parametros:
function configurar({ host = 'localhost', puerto = 3000, ssl = false } = {}) {
console.log(`${ssl ? 'https' : 'http'}://${host}:${puerto}`);
}
configurar({ ssl: true }); // usa defaults para host y puerto
configurar(); // usa todos los defaultsOptional chaining (?.)
Accede a propiedades profundas sin verificaciones manuales. Retorna undefined si alguna parte es null o undefined:
// Sin optional chaining
const ciudad = usuario && usuario.dirección && usuario.dirección.ciudad;
// Con optional chaining
const ciudad = usuario?.dirección?.ciudad;Funciona también con arrays (arr?.[0]) y métodos (obj.método?.()).
Nullish coalescing (??)
Proporciona un valor por defecto solo cuando el lado izquierdo es null o undefined:
const puerto = config.puerto ?? 3000;A diferencia de ||, no considera 0, '' o false como "vacios".
Operadores de asignación lógica
Combinan un operador lógico con asignación:
| Operador | Equivale a | Asigna cuando... |
|---|---|---|
a ||= b |
a = a || b |
a es falsy |
a ??= b |
a = a ?? b |
a es null/undefined |
a &&= b |
a = a && b |
a es truthy |
structuredClone
La forma nativa de hacer copias profundas (ES2022). Funciona con objetos, arrays, Date, Map, Set, RegExp y más:
const copia = structuredClone(original);No funciona con funciones, nodos DOM ni Symbols.
Map y Set
Map
Similar a un objeto, pero con ventajas:
- Las claves pueden ser cualquier tipo (objetos, funciones, etc.)
- Mantiene el orden de inserción
- Tiene propiedad
.size - Mejor rendimiento para adiciones/eliminaciones frecuentes
Set
Coleccion de valores unicos. Excelente para eliminar duplicados y verificar pertenencia:
const ids = new Set();
ids.add(1);
ids.add(2);
ids.add(1); // ignorado (ya existe)
ids.has(1); // true
ids.size; // 2Iteradores personalizados
Cualquier objeto puede ser iterable implementando [Symbol.iterator](). Esto permite usarlo con for...of, spread, destructuring y más.
Proxy
Un Proxy envuelve un objeto e intercepta operaciones como lectura, escritura y eliminacion de propiedades. Es útil para validación, logging, y patrones reactivos.
Práctica
- Elimina duplicados con Set: Dado un array con valores repetidos, usa
new Set()y el spread operator para crear un nuevo array sin duplicados. Verifica el resultado conconsole.log. - Crea un cache con Map: Implementa una funcion
obtenerConCache(clave, funcionCostosa)que almacene resultados en unMap. Si la clave ya existe, retorna el valor cacheado; si no, ejecuta la funcion, guarda el resultado y lo retorna. - Valida con Proxy: Crea un
Proxysobre un objeto vacio que valide que la propiedademailsiempre contenga un@al asignarla. Si no lo contiene, lanza unTypeError.
En la siguiente leccion aplicaras todo lo aprendido en un proyecto integrador.
// === DESTRUCTURING AVANZADO ===
// Destructuring con renombre y default
const respuesta = { data: { user: 'Carlos' }, status: 200 };
const { data: { user: nombre }, status = 0 } = respuesta;
console.log(nombre); // 'Carlos'
// Destructuring en parametros de función
function crearPerfil({ nombre, edad, rol = 'usuario' }) {
return `${nombre} (${edad}) - ${rol}`;
}
crearPerfil({ nombre: 'Ana', edad: 25 });
// === OPTIONAL CHAINING ===
const config = { db: { host: 'localhost' } };
const puerto = config.db?.puerto ?? 3000;
const nombre2 = config.auth?.user?.nombre ?? 'anonimo';
// Optional chaining con métodos
const resultado = arreglo?.find?.(x => x.id === 1);
// === LOGICAL ASSIGNMENT ===
let opciones = { tema: '', idioma: null };
opciones.tema ||= 'claro'; // asigna si es falsy
opciones.idioma ??= 'es'; // asigna si es null/undefined
opciones.debug &&= false; // asigna si es truthy
// === STRUCTUREDCLONE ===
const original = {
usuario: { nombre: 'Carlos', tags: ['dev'] },
fecha: new Date(),
};
const copia = structuredClone(original);
copia.usuario.tags.push('senior');
console.log(original.usuario.tags); // ['dev'] (no afectado)
// === MAP Y SET ===
const cache = new Map();
cache.set('user:1', { nombre: 'Carlos' });
cache.set('user:2', { nombre: 'Ana' });
console.log(cache.get('user:1')); // {nombre: 'Carlos'}
console.log(cache.has('user:3')); // false
const unicos = new Set([1, 2, 2, 3, 3, 3]);
console.log([...unicos]); // [1, 2, 3]
// Eliminar duplicados de un array
const sinDuplicados = [...new Set(nombres)];
// === ITERADORES Y FOR...OF ===
// Objeto iterable personalizado
const rango = {
desde: 1,
hasta: 5,
[Symbol.iterator]() {
let actual = this.desde;
const hasta = this.hasta;
return {
next() {
return actual <= hasta
? { value: actual++, done: false }
: { done: true };
},
};
},
};
for (const n of rango) {
console.log(n); // 1, 2, 3, 4, 5
}
// === PROXY ===
const validado = new Proxy({}, {
set(obj, prop, valor) {
if (prop === 'edad' && typeof valor !== 'number') {
throw new TypeError('edad debe ser un número');
}
obj[prop] = valor;
return true;
},
});
validado.nombre = 'Carlos'; // OK
validado.edad = 28; // OK
// validado.edad = 'veintiocho'; // TypeError!
Inicia sesión para guardar tu progreso