Principales errores de desarrolladores JavaScript principiantes: nivel avanzado
Cuando ya has dominado la sintaxis básica de JavaScript y has escrito un par de scripts para el navegador o Node.js, parece que lo más difícil ya pasó. Pero es precisamente en la etapa de transición a proyectos reales (a menudo en el lado del servidor con Node.js) donde los desarrolladores se enfrentan a errores engañosos que no rompen el código de inmediato, pero que provocan bugs difíciles de detectar, fugas de memoria y comportamientos inesperados. En este artículo analizaremos las 4 principales errores avanzados que cometen los desarrolladores JavaScript principiantes y mostraremos cómo evitarlos.
1. Falta de comprensión del funcionamiento de los closures en bucles (Closures in Loops)
Un problema clásico que ha pasado del JavaScript del navegador a Node.js. Muchos saben que var tiene ámbito de función, no de bloque, pero el error ocurre incluso con let cuando se usan incorrectamente callbacks asíncronos.
Problema: Creas un array de funciones en un bucle y esperas que cada función recuerde su propio valor del contador. En cambio, todas las funciones hacen referencia al último valor.
// ❌ Error: todas las llamadas devolverán 3const functions = [];for (var i = 0; i < 3; i++) { functions.push(() => console.log(i));}functions.forEach(fn => fn()); // 3, 3, 3¿Por qué sucede esto? El closure captura no el valor de la variable i, sino una referencia a la variable misma. Para cuando se llama a la función, el bucle ya ha terminado y i es igual a 3.
Solución (para Node.js): Usa let para el ámbito de bloque o crea un nuevo closure mediante IIFE (Immediately Invoked Function Expression).
// ✅ Corrección con letconst functions = [];for (let i = 0; i < 3; i++) { functions.push(() => console.log(i));}functions.forEach(fn => fn()); // 0, 1, 2
// ✅ Corrección con closure (función invocada inmediatamente)for (var i = 0; i < 3; i++) { (function(j) { functions.push(() => console.log(j)); })(i);}2. Ignorar la asincronía: «Carrera» de promesas y pérdida del contexto this
Node.js es un entorno asíncrono. Uno de los errores más comunes es intentar usar el resultado de una operación asíncrona antes de que termine, o perder el contexto this dentro de los métodos.
Ejemplo 1: Condición de carrera (Race condition)
// ❌ Error: el resultado puede ser undefinedlet userData;fetchUserData().then(data => { userData = data;});console.log(userData); // undefined — el código síncrono se ejecutó antesEjemplo 2: Pérdida de this en un callback
class Logger { constructor(prefix) { this.prefix = prefix; } logLater() { setTimeout(function() { console.log(this.prefix); // undefined — this hace referencia al objeto global }, 100); }}const logger = new Logger('INFO:');logger.logLater(); // undefinedSolución: Usa siempre async/await para operaciones secuenciales y funciones flecha para preservar el contexto.
// ✅ Corrección con async/awaitasync function getUserData() { const userData = await fetchUserData(); console.log(userData); // ahora los datos definitivamente están}
// ✅ Corrección con arrow functionclass Logger { constructor(prefix) { this.prefix = prefix; } logLater() { setTimeout(() => { console.log(this.prefix); // INFO: }, 100); }}3. Manejo incorrecto de errores en cadenas de promesas y streams
En Node.js, muchas operaciones devuelven promesas o streams. Los desarrolladores principiantes a menudo olvidan manejar los errores en medio de una cadena o en streams, lo que provoca fallos silenciosos