Volver al curso

JavaScript Desde Cero: Tu Primer Lenguaje de Programación

leccion
4 / 22
beginner
8 horas
Fundamentos de JavaScript

console.log() y Debugging Básico

Lectura
30 min~11 min lectura

console.log() y Debugging Básico

Objetivos de aprendizaje

Al finalizar esta lección serás capaz de:

  • Dominar todos los métodos del objeto console para diferentes propósitos
  • Utilizar las herramientas de desarrollo del navegador para depurar código
  • Aplicar técnicas de debugging sistemático para encontrar y corregir errores
  • Leer e interpretar mensajes de error de JavaScript correctamente
  • Escribir código más limpio usando logging estratégico

1. El objeto console a fondo

Ya conocés console.log(), pero el objeto console tiene muchos más métodos que te van a hacer la vida más fácil como desarrollador.

console.log() y sus variantes

// console.log() - Mensaje general
console.log("Información general");

// console.info() - Información (ícono de info en algunos navegadores)
console.info("Este es un dato informativo");

// console.warn() - Advertencia (texto amarillo con ícono de triángulo)
console.warn("¡Cuidado! Esta función será deprecada en la próxima versión");

// console.error() - Error (texto rojo con stack trace)
console.error("Error crítico: No se pudo conectar a la base de datos");

// console.debug() - Debug (solo visible si el nivel de log está habilitado)
console.debug("Variable x vale:", 42);

console.log() con múltiples argumentos

No necesitás concatenar strings. Podés pasar múltiples argumentos separados por coma:

let usuario = "Ana";
let edad = 28;
let activo = true;

// ❌ Concatenación (engorrosa)
console.log("Usuario: " + usuario + ", Edad: " + edad + ", Activo: " + activo);

// ✅ Múltiples argumentos (más limpio)
console.log("Usuario:", usuario, "| Edad:", edad, "| Activo:", activo);

// ✅ Template literal (lo más moderno)
console.log(`Usuario: ${usuario} | Edad: ${edad} | Activo: ${activo}`);

// ✅ Pasar un objeto directamente (permite expandir en la consola)
console.log({ usuario, edad, activo });

console.table() — Visualizar datos tabulares

// Con arrays
const frutas = ["Manzana", "Banana", "Cereza", "Durazno"];
console.table(frutas);
// Muestra una tabla con índice y valor

// Con arrays de objetos (MUY útil)
const estudiantes = [
  { nombre: "Ana", nota: 9, aprobado: true },
  { nombre: "Carlos", nota: 5, aprobado: false },
  { nombre: "María", nota: 8, aprobado: true },
  { nombre: "Luis", nota: 7, aprobado: true }
];
console.table(estudiantes);
// Muestra una tabla completa con columnas por cada propiedad

// Seleccionar columnas específicas
console.table(estudiantes, ["nombre", "nota"]);

console.group() y console.groupCollapsed() — Organizar mensajes

console.group("🔍 Datos del pedido #1234");
console.log("Cliente: Juan Pérez");
console.log("Producto: Laptop HP");
console.log("Precio: $999.99");

  console.group("📦 Detalles de envío");
  console.log("Dirección: Av. Corrientes 1234");
  console.log("Ciudad: Buenos Aires");
  console.log("Código Postal: C1043");
  console.groupEnd();

console.log("Estado: Procesando");
console.groupEnd();

// groupCollapsed() empieza cerrado (ideal para logs extensos)
console.groupCollapsed("⚙️ Configuración del sistema");
console.log("Tema: Oscuro");
console.log("Idioma: Español");
console.log("Notificaciones: Activas");
console.groupEnd();

console.time() y console.timeEnd() — Medir rendimiento

console.time("Operación pesada");

// Simular una operación que tarda
let suma = 0;
for (let i = 0; i < 1000000; i++) {
  suma += i;
}

console.timeEnd("Operación pesada");
// Output: "Operación pesada: 12.345ms"

// Medir múltiples operaciones
console.time("Total");

console.time("Array.map");
const numeros = Array.from({ length: 100000 }, (_, i) => i);
const dobles = numeros.map(n => n * 2);
console.timeEnd("Array.map");

console.time("Array.filter");
const pares = numeros.filter(n => n % 2 === 0);
console.timeEnd("Array.filter");

console.timeEnd("Total");

console.count() y console.countReset() — Contar ejecuciones

function procesarClick(boton) {
  console.count(`Click en ${boton}`);
}

procesarClick("Guardar");  // Click en Guardar: 1
procesarClick("Cancelar"); // Click en Cancelar: 1
procesarClick("Guardar");  // Click en Guardar: 2
procesarClick("Guardar");  // Click en Guardar: 3

console.countReset("Click en Guardar");
procesarClick("Guardar");  // Click en Guardar: 1 (reiniciado)

console.assert() — Verificar condiciones

const edad = 15;

// Solo muestra el mensaje si la condición es FALSE
console.assert(edad >= 18, "El usuario es menor de edad");
// Muestra: Assertion failed: El usuario es menor de edad

console.assert(edad >= 0, "La edad no puede ser negativa");
// No muestra nada (la condición es true)

Estilos en console.log()

// Aplicar CSS a los mensajes
console.log(
  "%c¡JavaScript es genial!",
  "color: #f0db4f; background: #323330; font-size: 20px; padding: 10px; border-radius: 5px; font-weight: bold;"
);

// Múltiples estilos
console.log(
  "%cError %cen la línea 42",
  "color: red; font-weight: bold; font-size: 14px;",
  "color: gray; font-size: 14px;"
);

// ASCII art
console.log(`
%c
   ╔══════════════════╗
   ║  CURSALO v1.0    ║
   ║  JavaScript      ║
   ╚══════════════════╝
`, "color: #6366f1; font-family: monospace;");

2. Entendiendo los errores de JavaScript

Los errores no son tu enemigo — son tu GPS. Te dicen exactamente qué salió mal y dónde. Aprender a leerlos es una de las habilidades más valiosas que podés desarrollar.

Anatomía de un error

// Cuando algo falla, JavaScript muestra:
// 1. Tipo de error (SyntaxError, TypeError, ReferenceError, etc.)
// 2. Mensaje descriptivo
// 3. Stack trace (ruta de ejecución que causó el error)

try {
  let resultado = undefined.propiedad;
} catch (error) {
  console.log("Tipo:", error.name);       // "TypeError"
  console.log("Mensaje:", error.message);  // "Cannot read properties of undefined"
  console.log("Stack:", error.stack);      // Ubicación completa del error
}

Los tipos de error más comunes

// 1. SyntaxError — Error de sintaxis (código mal escrito)
// let x = ; // SyntaxError: Unexpected token ';'
// console.log("hola" // SyntaxError: missing ) after argument list

// 2. ReferenceError — Variable no definida
try {
  console.log(variableQueNoExiste);
} catch (e) {
  console.error(e); // ReferenceError: variableQueNoExiste is not defined
}

// 3. TypeError — Operación inválida sobre un tipo
try {
  null.toString();
} catch (e) {
  console.error(e); // TypeError: Cannot read properties of null
}

try {
  const num = 42;
  num(); // Intentar llamar un número como función
} catch (e) {
  console.error(e); // TypeError: num is not a function
}

// 4. RangeError — Valor fuera de rango
try {
  const arr = new Array(-1); // Tamaño negativo
} catch (e) {
  console.error(e); // RangeError: Invalid array length
}

// 5. URIError — Error en funciones URI
try {
  decodeURI("%");
} catch (e) {
  console.error(e); // URIError: URI malformed
}

Cómo leer un stack trace

function calcularDescuento(precio, porcentaje) {
  return precio.toFixed(2) * (1 - porcentaje / 100);
}

function procesarCompra(items) {
  let total = null; // Bug: debería ser un número
  return calcularDescuento(total, 10);
}

function checkout() {
  return procesarCompra(["item1", "item2"]);
}

// checkout();
// TypeError: Cannot read properties of null (reading 'toFixed')
//   at calcularDescuento (script.js:2:16)    ← Aquí está el error
//   at procesarCompra (script.js:7:10)        ← Llamado desde aquí
//   at checkout (script.js:11:10)              ← Que fue llamado desde aquí

// El stack trace se lee DE ARRIBA A ABAJO:
// Línea 1: Dónde ocurrió el error
// Líneas siguientes: La cadena de llamadas que llevó al error

3. Técnicas de debugging efectivas

Técnica 1: Console.log estratégico

No pongas console.log() al azar. Usá un enfoque sistemático:

function calcularTotal(items) {
  console.log("[calcularTotal] Input:", items); // Log de entrada
  
  let subtotal = 0;
  for (const item of items) {
    console.log("[calcularTotal] Procesando:", item.nombre, "Precio:", item.precio);
    subtotal += item.precio * item.cantidad;
  }
  
  console.log("[calcularTotal] Subtotal:", subtotal); // Log intermedio
  
  const iva = subtotal * 0.16;
  const total = subtotal + iva;
  
  console.log("[calcularTotal] Output:", { subtotal, iva, total }); // Log de salida
  return total;
}

Técnica 2: El debugger del navegador

La palabra clave debugger pausa la ejecución del código en ese punto:

function calcularDescuento(precio, porcentaje) {
  debugger; // ← La ejecución se pausa aquí
  // En Chrome DevTools podés ver todas las variables,
  // avanzar paso a paso, y entender el flujo
  const descuento = precio * (porcentaje / 100);
  return precio - descuento;
}

En Chrome DevTools (F12 → Sources), cuando el código se pausa podés:

  • Step Over (F10): Ejecutar la línea actual y pasar a la siguiente
  • Step Into (F11): Entrar dentro de una función
  • Step Out (Shift+F11): Salir de la función actual
  • Watch: Agregar expresiones para monitorear
  • Scope: Ver todas las variables y sus valores
  • Call Stack: Ver la cadena de llamadas

Técnica 3: try-catch para manejar errores

function dividir(a, b) {
  if (typeof a !== "number" || typeof b !== "number") {
    throw new Error("Ambos argumentos deben ser números");
  }
  if (b === 0) {
    throw new Error("No se puede dividir por cero");
  }
  return a / b;
}

try {
  const resultado = dividir(10, 0);
  console.log(resultado);
} catch (error) {
  console.error("Ocurrió un error:", error.message);
  // "Ocurrió un error: No se puede dividir por cero"
} finally {
  console.log("Esto se ejecuta siempre, haya o no error");
}

Técnica 4: Breakpoints condicionales

En Chrome DevTools podés hacer clic derecho en un número de línea y seleccionar "Add conditional breakpoint". Esto pausa la ejecución solo cuando se cumple una condición:

// Si tenés un loop de 1000 iteraciones pero el bug ocurre en la iteración 500:
for (let i = 0; i < 1000; i++) {
  // Breakpoint condicional: i === 500
  procesarItem(items[i]);
}

Técnica 5: El método de bisección

Cuando no sabés dónde está el bug:

  1. Poné un console.log a la mitad del código
  2. Si el log se ejecuta correctamente, el bug está después → repetí en la segunda mitad
  3. Si el log no se ejecuta o muestra datos incorrectos, el bug está antes → repetí en la primera mitad
  4. Seguí dividiendo hasta encontrar la línea exacta
function procesoComplejo(datos) {
  // Paso 1
  const filtrados = datos.filter(d => d.activo);
  console.log("CHECKPOINT 1:", filtrados.length, "items filtrados");
  
  // Paso 2
  const transformados = filtrados.map(d => ({ ...d, precio: d.precio * 1.16 }));
  console.log("CHECKPOINT 2:", transformados[0]); // ¿El primer item se ve bien?
  
  // Paso 3
  const total = transformados.reduce((sum, d) => sum + d.precio, 0);
  console.log("CHECKPOINT 3:", total); // ¿El total es razonable?
  
  return total;
}

Errores comunes de principiantes
  1. Dejar console.log() en producción: Siempre limpiá tus logs antes de subir código. Existen herramientas como ESLint que te avisan.

  2. No leer el mensaje de error completo: El stack trace te dice exactamente dónde está el problema. Leelo completo antes de buscar en Google.

  3. Cambiar muchas cosas a la vez: Cuando debuggeás, cambiá UNA cosa y probá. Si cambiás 5 cosas y funciona, no sabés cuál era el problema.

  4. No usar breakpoints: console.log está bien, pero el debugger del navegador es más poderoso. Aprendé a usarlo.

  5. Ignorar warnings: Los console.warn() del navegador a menudo anticipan errores futuros. No los ignores.


Puntos clave de esta lección
  1. console.table() es la mejor forma de visualizar arrays de objetos.
  2. console.group() organiza mensajes relacionados en bloques colapsables.
  3. console.time() te permite medir el rendimiento de tu código con precisión.
  4. Los errores de JavaScript tienen un tipo, un mensaje y un stack trace — aprendé a leer los tres.
  5. Los errores más comunes son TypeError (operar sobre null/undefined), ReferenceError (variable no definida) y SyntaxError (código mal escrito).
  6. El debugger del navegador (Chrome DevTools) es más poderoso que console.log para debugging complejo.
  7. Usá el método de bisección para encontrar bugs rápidamente en código largo.

Quiz de autoevaluación

1. ¿Qué método de console muestra datos en formato tabla?
a) console.grid()
b) console.table()
c) console.matrix()
d) console.format()

2. ¿Qué tipo de error se produce al intentar usar una variable que no fue declarada?
a) TypeError
b) SyntaxError
c) ReferenceError
d) ValueError

3. ¿Qué hace la palabra clave debugger en JavaScript?
a) Elimina todos los bugs
b) Pausa la ejecución del código en ese punto
c) Muestra los errores en rojo
d) Crea un log automático

4. ¿En qué orden se lee un stack trace?
a) De abajo a arriba
b) De arriba a abajo (la primera línea es donde ocurrió el error)
c) Aleatorio
d) Solo importa la última línea

5. ¿Qué bloque se ejecuta siempre en un try-catch-finally?
a) try
b) catch
c) finally
d) Ninguno, depende del error

Respuestas: 1-b, 2-c, 3-b, 4-b, 5-c


💡 Concepto Clave

Revisemos los puntos más importantes de esta lección antes de continuar.

Ejercicio práctico

Misión: Detective de bugs

El siguiente código tiene 5 bugs ocultos. Tu misión es encontrarlos y corregirlos usando las técnicas de debugging que aprendiste. Usá console.log(), console.table(), typeof y el stack trace para diagnosticar cada error.

// Bug Hunt - Encontrá y corregí los 5 errores
function calcularFactura(items, descuento) {
  let subtotal = 0;
  
  for (let i = 0; i <= items.length; i++) { // Bug 1: ¿ves el problema?
    subtotal += items[i].precio * items[i].cantdad; // Bug 2: typo
  }
  
  const iva = subtotal * 0.16;
  const descuentoAplicado = subtotal * descuento; // Bug 3: ¿qué pasa si descuento es undefined?
  const total = subtotal + iva + descuentoAplicado; // Bug 4: ¿sumar o restar el descuento?
  
  return total.Fixed(2); // Bug 5: nombre del método incorrecto
}

const items = [
  { nombre: "Café", precio: 50, cantidad: 2 },
  { nombre: "Torta", precio: 120, cantidad: 1 },
  { nombre: "Jugo", precio: 35, cantidad: 3 }
];

console.log("Total: $" + calcularFactura(items, 0.1));

Corregí cada bug y explicá qué técnica usaste para encontrarlo.

🧠 Pon a prueba tu conocimiento
¿Cuál es el aspecto más importante que aprendiste en esta lección?
  • Comprendo el concepto principal y puedo explicarlo con mis palabras
  • Entiendo cómo aplicarlo en mi situación específica
  • Necesito repasar algunas partes antes de continuar
  • Quiero ver más ejemplos prácticos del tema
✅ ¡Excelente! Continúa con la siguiente lección para profundizar más.