1) Antes de empezar: cómo pensar los errores (y por qué no frustrarte)
Cuando empecé, los errores eran el pan de cada día. En mi caso, cambié el enfoque: dejé de verlos como “enemigos” y empecé a tratarlos como visitas frecuentes que te dejan aprendizaje si les ofreces una silla —y una consola abierta. Si tu meta es ser desarrollador/a web, los problemas se convierten en amigos que vuelven una y otra vez; lo importante es saber recibirlos: leer el mensaje de error, aislar el problema y probar hipótesis.
Principios mentales útiles
- Curiosidad sobre orgullo. No des por hecho que “debería funcionar”; pregúntate por qué no lo hace.
- Hipótesis pequeñas. Cambios mínimos → validaciones rápidas. Evita “toquetear todo”.
- Confirma con herramientas. DevTools, console.log, breakpoints y el stack trace son tu mapa.
- Documenta tu hallazgo. Un gist/notita por error resuelto; te ahorrarás horas en el futuro.
- Busca en fuentes confiables. Cuando me trabo, busco en sitios de referencia y comparo varias respuestas antes de aplicar la solución.
Inserción de experiencia: “No es motivo de frustración”: la frustración es señal de que estás a punto de aprender algo específico. Úsala para enfocarte.
2) Checklist de depuración rápida (consola, stack trace y breakpoint)
- Lee el mensaje completo. Copia el error exacto (“Cannot read properties of undefined…”) y obsérvalo.
- Ubica la línea. Haz clic en el enlace del error en la consola: te lleva al archivo/línea.
- Aísla el fragmento. Crea un repro mínimo (un HTML simple + tu script). Menos ruido = más claridad.
- console.log estratégico. Registra las variables clave justo antes de donde falla.
- Breakpoints y “Step into”. Pausa y recorre tu código paso a paso; mira el “Scope” (variables disponibles).
- Comprueba selectores. ¿Existe el elemento? ¿Se ejecuta el script antes de que el DOM cargue?
- Revisa imports. ¿La ruta es correcta? ¿El nombre exportado coincide?
- Prueba tipos. typeof y Array.isArray para confirmar lo que crees que recibes.
- Busca el patrón del error. Pega el mensaje en un buscador con “JavaScript” y mira soluciones comunes.
- Solución pequeña → commit. Valida y guarda el avance para no retroceder.
Inserción de experiencia: “Solo hay que saber resolverlos”: este checklist es mi ruta corta cuando algo rompe en producción o aparece un bug críptico.
3) Typos y mayúsculas/minúsculas: addEventListener, métodos del DOM y casing
Los typos son los reyes de los errores. JavaScript distingue mayúsculas/minúsculas: addEventListener no es addeventlistener. Igual con getElementById (no existe getElementsById). Lo mismo aplica a nombres de variables (usuarioNombre vs userNombre).
Patrones típicos y soluciones
- addEventListener no hace nada
- Causas: typo en el método; usas onclick en lugar de listener; elemento null.
- Solución: confirma el método y que el elemento exista antes del listener.
- document.querySelector("boton") devuelve null
- Causa: faltó el . o #.
- Solución: querySelector(".boton") para clase, ("#boton") para id; verifica que el elemento esté en el DOM al momento de ejecutar.
Snippet
<button id="save">Guardar</button>
<script>
const btn = document.querySelector("#save"); // ✅ id
if (!btn) throw new Error("No se encontró #save");
btn.addEventListener("click", () => console.log("OK"));
</script>
Inserción de experiencia: más de una vez he “arreglado” un bug con solo poner # donde escribí una clase sin punto. Respira, revisa, y listo.
4) Selectores que devuelven null: querySelector, clases y textContent
Cuando ves Cannot read properties of null (reading '…'), casi siempre accedes a una propiedad de algo que no existe.
Lista de verificación
- ¿El selector es correcto (.clase, #id, tag)?
- ¿El elemento existe en el HTML final (no en un template no renderizado)?
- ¿El script corre antes de que el DOM esté listo? Usa defer o DOMContentLoaded.
- ¿Estás en el shadow DOM? querySelector del documento no lo ve.
Snippet
<script defer src="app.js"></script>
document.addEventListener("DOMContentLoaded", () => {
const title = document.querySelector(".title");
if (!title) return console.warn("Falta .title");
title.textContent = "Hola, DOM";
});
5) Mensajes típicos y su solución: TypeError, ReferenceError, SyntaxError
- TypeError: Cannot read properties of undefined/null
- Causas: variable no inicializada; selector null; retorno inesperado.
- Solución: validación defensiva (if (!obj) { … }), valores por defecto y early returns.
- ReferenceError: X is not defined
- Causas: variable fuera de alcance; nombre mal escrito; script no cargado.
- Solución: revisa el scope, orden de scripts e imports.
- SyntaxError: Unexpected token …
- Causas: JSON con comillas simples, coma final, paréntesis o llaves desbalanceadas.
- Solución: valida con un linter y, para JSON, usa JSON.parse con JSON válido.
Snippet
// Evita reventar por undefined:
const email = user?.profile?.email ?? "(sin email)";
6) Lógica que falla en silencio: condiciones, Math.random() y casos reales
A veces no hay error en consola, pero la lógica no hace lo esperado.
Ejemplo clásico: cálculo de un número aleatorio entero en rango.
Patrón correcto
// entero [1, N]
const n = Math.floor(Math.random() * N) + 1;
Errores comunes
- Usar Math.round y crear sesgos.
- Olvidar el + 1 y nunca alcanzar el máximo.
- Comparaciones mal planteadas: if (valor) cuando 0 es válido.
Checklist de lógica
- Asegura valores iniciales.
- Escribe tests mínimos para cada rama.
- Loguea entradas/salidas en funciones críticas.
7) Igualdad == vs ===, coerción y undefined/null
La igualdad floja (==) hace coerción; === compara tipo y valor.
Usa === casi siempre y reserva == para casos donde entiendes y deseas la coerción.
Trampas comunes
- '' == 0 es true, pero '' === 0 es false.
- null == undefined es true, pero null === undefined es false.
Recomendación
- Activa un linter con la regla que favorezca ===.
- Normaliza entradas: convierte strings a número con Number() antes de comparar.
8) Asíncronía sin dolor: Promesas, async/await y errores comunes
Patrones de error
- Olvidar await → trabajas con una Promise en vez del valor.
- No capturar errores → fallos silenciosos.
- Correr en paralelo lo que es secuencial (o viceversa).
Snippet robusto
async function loadUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error("loadUser falló:", err);
return null; // fallback controlado
}
}
Buenas prácticas
- Usa Promise.all cuando las llamadas sean independientes.
- Envuelve await críticos en try/catch.
- Registra contexto en los errores (id, endpoint, payload).
Inserción de experiencia: cuando me atoro, vuelvo a lo básico: imprimo el tipo de lo que manejo (¿Promise, objeto, string?) y el problema canta solo.
9) Buenas prácticas: ESLint/Prettier, pruebas, manejo de errores y logging
- ESLint: atrapa typos, variables no usadas, == accidentales.
- Prettier: formato consistente que evita diffs ruidosos.
- Testing: un par de pruebas unitarias en funciones clave (Jest/Vitest).
- Manejo de errores: throw con mensajes útiles; errores personalizados.
- Logging: en desarrollo, console.*; en producción, un logger con niveles y trazas.
Ejemplo de error personalizado
class ValidationError extends Error {
constructor(message, field) {
super(message); this.name = "ValidationError"; this.field = field;
}
}
Recomendaciones clave (para evitar el 80% de los errores)
- Carga scripts con defer y ordena dependencias (módulos primero).
- Nombra con intención: verbos para funciones, sustantivos para datos.
- Valida entradas al borde del sistema (formularios, APIs).
- Guarda null/undefined para lo excepcional y usa valores por defecto.
- Tipa cuando sea posible (TypeScript o JSDoc) para descubrir errores antes.
- Registra contexto en los errores (id de usuario, endpoint, estado).
- Automatiza calidad: ESLint + Prettier en pre-commit; tests de humo en CI.
- Documenta tus hallazgos: un README “Errores frecuentes del proyecto”.
- Reproduce rápido en un sandbox; si no puedes reproducir, no lo has entendido.
- Revisa después de arreglar: ¿qué prueba evitará que vuelva a romperse?
Inserción de experiencia: “Buscar información en sitios confiables” me ha salvado mil veces; contrasta dos fuentes antes de aplicar un fix que no entiendes.
Conclusión
Equivocarte no es una excepción, es el flujo normal de aprender JavaScript. Con un checklist claro, algunos patrones en la cabeza y una actitud de investigación, los errores dejan de ser un muro y se vuelven pistas. Integra las recomendaciones, guarda tu tabla de diagnóstico a mano y, cada vez que un bug te visite, ofrécele una silla y pregúntale qué vino a enseñarte.