Skip to content

Top 100 Preguntas Completas de JavaScript

Esta guía cubre desde fundamentos hasta temas avanzados. Las preguntas 1-50 están en las guías anteriores.


¿Qué es? Patrón que garantiza una única instancia de una clase en toda la aplicación.

¿Para qué sirve? Configuración global, conexiones a BD, caché, loggers.

const Singleton = (function() {
let instance;
function createInstance() {
return { id: Math.random() };
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
const a = Singleton.getInstance();
const b = Singleton.getInstance();
console.log(a === b); // true

¿Qué es? Patrón que delega la creación de objetos a una función/clase especializada.

¿Para qué sirve? Desacoplar la creación de objetos de su uso. Crear objetos según condiciones.

class CarFactory {
createCar(type) {
switch(type) {
case 'sedan':
return new Sedan();
case 'suv':
return new SUV();
default:
throw new Error('Tipo no soportado');
}
}
}
const factory = new CarFactory();
const miCarro = factory.createCar('sedan');

¿Qué es? Patrón donde objetos (observers) se suscriben a eventos de otro objeto (subject).

¿Para qué sirve? Event emitters, pub/sub, actualizaciones reactivas.

class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(cb => cb(data));
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event]
.filter(cb => cb !== callback);
}
}
}

¿Qué es? Patrón que añade funcionalidad a una función/objeto sin modificar su código original.

¿Para qué sirve? Logging, caching, validación, permisos.

function withLogging(fn) {
return function(...args) {
console.log(`Llamando ${fn.name} con:`, args);
const result = fn.apply(this, args);
console.log(`Resultado:`, result);
return result;
};
}
function sumar(a, b) {
return a + b;
}
const sumarConLog = withLogging(sumar);
sumarConLog(2, 3);

¿Qué es? Transformar una función de múltiples argumentos en una secuencia de funciones de un argumento.

¿Para qué sirve? Crear funciones parcialmente aplicadas, composición funcional.

// Función normal
function sumar(a, b, c) {
return a + b + c;
}
// Función currificada
function sumarCurry(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
// Uso
sumarCurry(1)(2)(3); // 6
// Con arrow functions
const curry = a => b => c => a + b + c;

¿Qué es? Combinar funciones simples para crear funciones más complejas.

Tipos: compose (derecha a izquierda), pipe (izquierda a derecha).

const compose = (...fns) => x =>
fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => x =>
fns.reduce((acc, fn) => fn(acc), x);
const addOne = x => x + 1;
const double = x => x * 2;
const square = x => x * x;
const composed = compose(square, double, addOne);
console.log(composed(2)); // ((2+1)*2)^2 = 36

¿Qué es? Técnica de optimización que cachea resultados de funciones para evitar recálculos.

¿Para qué sirve? Funciones costosas con los mismos argumentos repetidos (ej: Fibonacci).

function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const fibonacci = memoize(function(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});

¿Qué es? Paradigma basado en funciones puras, inmutabilidad y composición.

Principios: Funciones puras, sin efectos secundarios, datos inmutables, funciones como valores.

// Principios:
// 1. Funciones puras
// 2. Inmutabilidad
// 3. Composición
// 4. Evitar efectos secundarios
// Imperativo vs Funcional
// Imperativo
let total = 0;
for (let i = 0; i < nums.length; i++) {
total += nums[i];
}
// Funcional
const total = nums.reduce((acc, n) => acc + n, 0);

59. ¿Qué es recursión y tail recursion?

Section titled “59. ¿Qué es recursión y tail recursion?”

Recursión: Función que se llama a sí misma.

Tail recursion: La llamada recursiva es la última operación. Puede optimizarse para evitar stack overflow.

// Recursión normal
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// Tail recursion (optimizable)
function factorialTail(n, acc = 1) {
if (n <= 1) return acc;
return factorialTail(n - 1, n * acc);
}

¿Qué es? Patrón que define una familia de algoritmos intercambiables.

¿Para qué sirve? Cambiar comportamiento en runtime sin modificar el código cliente.

const strategies = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b
};
function calculate(strategy, a, b) {
return strategies[strategy](a, b);
}
calculate('add', 5, 3); // 8
calculate('multiply', 5, 3); // 15

¿Qué es? Patrón que encapsula una acción como objeto.

¿Para qué sirve? Undo/redo, colas de comandos, logging de acciones.

class Calculator {
constructor() {
this.value = 0;
this.history = [];
}
execute(command) {
this.value = command.execute(this.value);
this.history.push(command);
}
undo() {
const command = this.history.pop();
if (command) {
this.value = command.undo(this.value);
}
}
}
class AddCommand {
constructor(value) {
this.value = value;
}
execute(current) { return current + this.value; }
undo(current) { return current - this.value; }
}

¿Qué es? Evaluar expresiones solo cuando se necesitan, no antes.

¿Para qué sirve? Trabajar con secuencias infinitas, mejorar performance.

function* lazyRange(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
// Solo calcula cuando se necesita
const range = lazyRange(1, 1000000);
console.log(range.next().value); // 1
console.log(range.next().value); // 2

¿Qué es? Cadena de funciones que procesan una request/context secuencialmente.

¿Para qué sirve? Express.js, Redux, pipelines de procesamiento.

class Pipeline {
constructor() {
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
return this;
}
execute(context) {
const runner = (index) => {
if (index < this.middlewares.length) {
this.middlewares[index](context, () => runner(index + 1));
}
};
runner(0);
}
}
const pipeline = new Pipeline();
pipeline
.use((ctx, next) => { ctx.a = 1; next(); })
.use((ctx, next) => { ctx.b = 2; next(); });

¿Qué es? Patrón donde publishers envían mensajes sin saber quién los recibe.

Diferencia con Observer: Pub/Sub tiene un intermediario (broker), Observer es directo.

const PubSub = {
subscribers: {},
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(callback);
return () => this.unsubscribe(event, callback);
},
publish(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(cb => cb(data));
}
},
unsubscribe(event, callback) {
if (this.subscribers[event]) {
this.subscribers[event] = this.subscribers[event]
.filter(cb => cb !== callback);
}
}
};

65. ¿Qué es inmutabilidad y cómo lograrla?

Section titled “65. ¿Qué es inmutabilidad y cómo lograrla?”

¿Qué es? No modificar datos existentes, crear copias con los cambios.

¿Para qué sirve? Predecibilidad, debugging, React/Redux, evitar bugs.

// Mutable (evitar)
const arr = [1, 2, 3];
arr.push(4); // Modifica el original
// Inmutable
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // Nuevo array
// Object.freeze (shallow)
const obj = Object.freeze({ a: 1 });
// Deep freeze
function deepFreeze(obj) {
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'object') {
deepFreeze(obj[key]);
}
});
return Object.freeze(obj);
}

¿Qué es? Proceso automático que libera memoria de objetos no accesibles.

Algoritmo: Mark-and-sweep. Marca objetos alcanzables desde root, elimina el resto.

67. ¿Qué son memory leaks y cómo evitarlos?

Section titled “67. ¿Qué son memory leaks y cómo evitarlos?”

¿Qué es? Memoria que no se libera porque aún hay referencias a objetos no usados.

Causas comunes: Variables globales, closures, event listeners, timers.

// Causas comunes:
// 1. Variables globales accidentales
function leak() {
leaked = "soy global"; // Sin var/let/const
}
// 2. Closures que retienen referencias
function createClosure() {
const largeData = new Array(1000000);
return function() {
console.log(largeData.length);
};
}
// 3. Event listeners no removidos
element.addEventListener('click', handler);
// Olvidar: element.removeEventListener('click', handler);
// 4. Timers no limpiados
const id = setInterval(() => {}, 1000);
// Olvidar: clearInterval(id);

¿Qué es? API para ejecutar código sincronizado con el refresh del monitor (60fps).

¿Para qué sirve? Animaciones suaves. Mejor que setInterval porque se pausa en tabs inactivos.

function animate() {
// Actualizar animación
element.style.left = position + 'px';
position++;
if (position < 300) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
// Mejor que setInterval para animaciones (60fps)

¿Qué es? Threads en segundo plano para ejecutar JavaScript sin bloquear la UI.

¿Para qué sirve? Cálculos pesados, procesamiento de datos, sin congelar la página.

main.js
const worker = new Worker('worker.js');
worker.postMessage({ data: [1, 2, 3, 4, 5] });
worker.onmessage = function(e) {
console.log('Resultado:', e.data);
};
// worker.js
self.onmessage = function(e) {
const result = e.data.data.map(n => n * 2);
self.postMessage(result);
};

¿Qué es? Script que actúa como proxy entre la app y la red.

¿Para qué sirve? PWAs, offline support, caching, push notifications.

// Registro
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
// sw.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll(['/index.html', '/styles.css']);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});

¿Qué es? Cargar recursos solo cuando se necesitan, no al inicio.

¿Para qué sirve? Mejorar tiempo de carga inicial, reducir ancho de banda.

// Imágenes
<img loading="lazy" src="imagen.jpg" />
// Módulos dinámicos
const module = await import('./heavyModule.js');
// React lazy
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

¿Qué es? Dividir el bundle en partes más pequeñas que se cargan bajo demanda.

¿Cómo? Dynamic imports (import()), React.lazy, configuración de bundler.

// Webpack dynamic imports
import('./module').then(module => {
module.default();
});
// React con Suspense
const LazyComponent = React.lazy(() => import('./Component'));
function App() {
return (
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
);
}

¿Qué es? Técnica que elimina código no utilizado (dead code) del bundle final.

Requisito: Usar ES modules (import/export). CommonJS no es tree-shakeable.

utils.js
export function usada() { }
export function noUsada() { }
// main.js
import { usada } from './utils';
// noUsada() será eliminada del bundle

Consejos: Cachear length, evitar accesos repetidos al DOM, usar métodos de array cuando sea legible.

// Malo - accede a length en cada iteración
for (let i = 0; i < array.length; i++) {}
// Mejor - cachea length
for (let i = 0, len = array.length; i < len; i++) {}
// Mejor aún - usa métodos de array
array.forEach(item => {});
array.map(item => item * 2);
// Para performance crítica - for...of
for (const item of array) {}

¿Qué es? Representación en memoria del DOM real (objeto JavaScript).

¿Para qué sirve? Minimizar manipulaciones costosas del DOM. React compara VDOMs y aplica solo cambios necesarios (reconciliación).

¿Qué es? Secuencia de pasos del navegador para convertir HTML/CSS/JS en píxeles.

Optimización: Minimizar CSS crítico, diferir JS no esencial, reducir render-blocking resources.

Pasos:

  1. DOM Construction
  2. CSSOM Construction
  3. Render Tree
  4. Layout
  5. Paint

Reflow: Recalcular geometría (posición, tamaño). Costoso.

Repaint: Redibujar apariencia (color, sombra). Menos costoso.

// Reflow (costoso) - cambia geometría
element.style.width = '100px';
element.style.height = '100px';
// Repaint (menos costoso) - cambia apariencia
element.style.color = 'red';
element.style.backgroundColor = 'blue';
// Optimización - batch changes
element.style.cssText = 'width: 100px; height: 100px;';
// O usar clases CSS

¿Qué es? Reutilizar objetos en vez de crear/destruir constantemente.

¿Para qué sirve? Juegos, animaciones, objetos costosos de crear.

class ObjectPool {
constructor(createFn, size = 10) {
this.createFn = createFn;
this.pool = Array(size).fill(null).map(() => createFn());
}
acquire() {
return this.pool.pop() || this.createFn();
}
release(obj) {
this.pool.push(obj);
}
}

APIs: performance.mark/measure, console.time, Chrome DevTools Performance tab.

// Performance API
performance.mark('start');
// ... código a medir
performance.mark('end');
performance.measure('Mi medición', 'start', 'end');
const measures = performance.getEntriesByName('Mi medición');
console.log(measures[0].duration);
// console.time
console.time('operacion');
// ... código
console.timeEnd('operacion');

¿Qué es? Tipo de dato para enteros arbitrariamente grandes (más allá de Number.MAX_SAFE_INTEGER).

Sintaxis: 123n o BigInt("123").

// Number tiene límite
const max = Number.MAX_SAFE_INTEGER; // 9007199254740991
// BigInt para números grandes
const big = 9007199254740991n;
const big2 = BigInt("9007199254740991");
// Operaciones
const suma = big + 1n;
// No se puede mezclar con Number sin conversión

¿Qué es? Cross-Site Scripting: inyección de scripts maliciosos en páginas web.

Prevención: Escapar output, usar textContent en vez de innerHTML, CSP headers.

// Cross-Site Scripting - inyección de scripts maliciosos
// Vulnerable
element.innerHTML = userInput;
// Seguro
element.textContent = userInput;
// O sanitizar
function sanitize(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}

¿Qué es? Cross-Site Request Forgery: ataque que fuerza al usuario a ejecutar acciones no deseadas.

Prevención: Tokens CSRF, SameSite cookies, verificar Origin header.

¿Qué es? Cross-Origin Resource Sharing: mecanismo que permite requests entre diferentes orígenes.

¿Cómo funciona? El servidor incluye headers Access-Control-Allow-*.

// Cross-Origin Resource Sharing
// Servidor debe incluir headers:
// Access-Control-Allow-Origin: *
// Access-Control-Allow-Methods: GET, POST
// Fetch con CORS
fetch('https://api.externa.com/data', {
mode: 'cors',
credentials: 'include'
});

¿Qué es? Header HTTP que especifica qué recursos pueden cargarse.

¿Para qué sirve? Prevenir XSS, clickjacking, inyección de recursos maliciosos.

// Header HTTP
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.com

Reglas: Nunca en código fuente, usar env vars, httpOnly cookies para tokens, nunca localStorage para auth.

// Nunca en código
const API_KEY = "abc123"; // MAL
// Variables de entorno
const API_KEY = process.env.API_KEY;
// Nunca en localStorage para tokens sensibles
// Usar httpOnly cookies para auth tokens

¿Qué es? Función que ejecuta strings como código JavaScript.

¿Por qué evitarlo? Riesgo de seguridad (inyección), lento, difícil de debuggear.

// eval ejecuta código arbitrario - PELIGROSO
eval("alert('hacked')");
// Alternativas seguras
// Para JSON
JSON.parse(jsonString);
// Para expresiones matemáticas
new Function('return ' + expression)();

87. ¿Qué es el principio de menor privilegio?

Section titled “87. ¿Qué es el principio de menor privilegio?”

¿Qué es? Dar solo los permisos mínimos necesarios para funcionar.

En JS: Limitar scope (const/let), encapsular código, módulos, closures.

Regla: Validar en cliente (UX) Y en servidor (seguridad). Nunca confiar solo en validación del cliente.

function validateEmail(email) {
const regex = /^[^s@]+@[^s@]+.[^s@]+$/;
return regex.test(email);
}
function sanitizeInput(input) {
return input
.trim()
.replace(/[<>]/g, '');
}
// Siempre validar en servidor también

¿Qué es? Archivos que mapean código minificado/transpilado al fuente original.

¿Para qué sirve? Debugging en producción. Cuidado: No exponer si el código es sensible.

90. ¿Qué es Subresource Integrity (SRI)?

Section titled “90. ¿Qué es Subresource Integrity (SRI)?”

¿Qué es? Verificar que recursos externos (CDN) no han sido modificados.

¿Cómo? Hash del contenido esperado en el atributo integrity.

<script
src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/..."
crossorigin="anonymous">
</script>

¿Qué es? Operador que accede a propiedades anidadas sin error si alguna es null/undefined.

const user = { profile: { name: 'Juan' } };
const city = user?.address?.city; // undefined, no error

¿Qué es? Operador que retorna el lado derecho solo si el izquierdo es null/undefined (no 0 o ”).

const value = null ?? 'default'; // 'default'
const zero = 0 ?? 'default'; // 0

¿Qué es? Espera a que TODAS las promises terminen (resueltas o rechazadas). Nunca rechaza.

const results = await Promise.allSettled([p1, p2, p3]);
// Siempre resuelve, nunca rechaza

¿Qué es? Referencia al objeto global que funciona en cualquier entorno (browser, Node, Worker).

// Funciona en todos los entornos
globalThis.myGlobal = 'value';
// Browser: window, Node: global, Worker: self

¿Qué es? Objeto con metadatos del módulo actual (URL, env vars en Vite, etc.).

console.log(import.meta.url);
// URL del módulo actual

96. ¿Qué es String.prototype.replaceAll?

Section titled “96. ¿Qué es String.prototype.replaceAll?”

¿Qué es? Método que reemplaza TODAS las ocurrencias de un string (no solo la primera).

const str = 'foo-bar-baz';
str.replaceAll('-', '_'); // 'foo_bar_baz'

¿Qué es? Resuelve con la PRIMERA promise que tenga éxito. Solo rechaza si TODAS fallan.

const first = await Promise.any([p1, p2, p3]);
// Primera que resuelva exitosamente

98. ¿Qué son los Logical Assignment Operators?

Section titled “98. ¿Qué son los Logical Assignment Operators?”

¿Qué es? Combinan operadores lógicos con asignación: ||=, &&=, ??=.

// ||= (or assignment)
x ||= y; // x = x || y
// &&= (and assignment)
x &&= y; // x = x && y
// ??= (nullish assignment)
x ??= y; // x = x ?? y

¿Qué es? Referencia débil a un objeto que no previene garbage collection.

¿Para qué sirve? Caches, evitar memory leaks en referencias circulares.

let obj = { data: 'importante' };
const weakRef = new WeakRef(obj);
// Puede ser garbage collected
obj = null;
// Acceder (puede ser undefined)
const deref = weakRef.deref();

¿Qué es? API para ejecutar código cuando un objeto es garbage collected.

Uso: Limpieza de recursos, logging, debugging.

const registry = new FinalizationRegistry((heldValue) => {
console.log(`${heldValue} fue recolectado`);
});
let obj = { data: 'test' };
registry.register(obj, 'mi objeto');
obj = null; // Eventualmente: "mi objeto fue recolectado"

🐝