1. Variables y Tipos de datos

Una variable es un contenedor con nombre que almacena un valor. En JavaScript se declaran con let, const o var.

// Declarar una variable con let
let nombre = "Ana";
let edad   = 22;

// Declarar una constante (no se puede reasignar)
const PI = 3.14159;

// Usar las variables
console.log(nombre);  // → "Ana"
console.log(edad + 5); // → 27

let, const y var

let
  • Bloque de alcance (block scope)
  • Se puede reasignar
  • No se puede redeclarar en el mismo bloque
  • ✅ Recomendado para valores que cambian
const
  • Bloque de alcance (block scope)
  • No se puede reasignar
  • No se puede redeclarar
  • ✅ Recomendado por defecto (la mayoría de casos)
var
  • Alcance de función (function scope)
  • Se puede reasignar y redeclarar
  • Tiene hoisting (se "sube" al inicio)
  • ⚠️ Evitar en código moderno

Regla práctica: Usa const siempre. Cambia a let solo cuando necesites reasignar el valor. Nunca uses var en código nuevo.

Tipos de datos primitivos

JavaScript tiene 7 tipos primitivos. Los tipos se determinan automáticamente — no se declaran explícitamente.

string
"Hola, mundo"
number
42 / 3.14
boolean
true / false
null
null
undefined
undefined
array (objeto)
[1, 2, 3]
object
{nombre: "Ana"}
// typeof → averigua el tipo de un valor
typeof "hola"      // → "string"
typeof 42          // → "number"
typeof true        // → "boolean"
typeof null        // → "object"  (⚠️ bug histórico de JS)
typeof undefined   // → "undefined"
typeof []          // → "object"
typeof {}          // → "object"

Strings — operaciones comunes

const texto = "JavaScript";

texto.length;              // → 10
texto.toUpperCase();       // → "JAVASCRIPT"
texto.toLowerCase();       // → "javascript"
texto.includes("Script");  // → true
texto.slice(0, 4);        // → "Java"
texto.replace("Java", "Type"); // → "TypeScript"
texto.split("a");          // → ["J", "v", "Script"]

// Template literals — strings con interpolación
const nombre = "Ana";
const saludo = `Hola, ${nombre}! Tienes ${2024 - 2002} años.`;
// → "Hola, Ana! Tienes 22 años."

Arrays — listas ordenadas

const frutas = ["manzana", "pera", "uva"];

frutas[0];           // → "manzana" (índice empieza en 0)
frutas.length;       // → 3
frutas.push("kiwi"); // agrega al final → ["manzana","pera","uva","kiwi"]
frutas.pop();        // elimina el último → ["manzana","pera","uva"]
frutas.includes("pera"); // → true
frutas.indexOf("uva");  // → 2

// Recorrer un array
frutas.forEach(function(fruta) {
  console.log(fruta);
});

Objetos — pares clave: valor

const persona = {
  nombre: "Ana",
  edad:   22,
  activa: true
};

// Acceder a propiedades
persona.nombre;        // → "Ana"   (notación de punto)
persona["edad"];      // → 22     (notación de corchetes)

// Agregar o modificar
persona.ciudad = "Bogotá";
persona.edad = 23;

// Destructuring — extraer propiedades en variables
const { nombre, edad } = persona;
console.log(nombre); // → "Ana"

▶ Demo interactivo — typeof

// El resultado aparecerá aquí

2. Operadores y Expresiones

Los operadores realizan operaciones sobre valores (operandos). Una expresión es cualquier fragmento de código que produce un valor.

Operadores aritméticos

10 + 3   // → 13   (suma)
10 - 3   // → 7    (resta)
10 * 3   // → 30   (multiplicación)
10 / 3   // → 3.33 (división)
10 % 3   // → 1    (módulo — resto de la división)
2  ** 8  // → 256  (potencia)

// Incremento y decremento
let x = 5;
x++;   // x = 6  (post-incremento)
x--;   // x = 5  (post-decremento)
++x;   // x = 6  (pre-incremento)

Operadores de comparación

// == vs === → SIEMPRE usa ===
5 == "5"   // → true   (convierte tipos, peligroso)
5 === "5"  // → false  (compara valor Y tipo, correcto)
5 !== 3   // → true   (diferente, estricto)

10 > 5    // → true
10 >= 10  // → true
3  < 7    // → true
3  <= 2   // → false

Regla de oro: Usa siempre === (igualdad estricta) y !== (desigualdad estricta). El operador == hace conversiones de tipo automáticas que producen resultados sorprendentes.

Operadores lógicos

// && → AND (Y): ambos deben ser true
true  && true   // → true
true  && false  // → false

// || → OR (O): basta con que uno sea true
false || true   // → true
false || false  // → false

// !  → NOT (NO): invierte el valor
!true            // → false
!false           // → true

// Operador nullish coalescing ?? → fallback si null/undefined
const nombre = null ?? "Invitado";  // → "Invitado"

// Encadenamiento opcional ?. → evita errores con null
const usuario = null;
usuario?.nombre;  // → undefined (sin error)

▶ Demo interactivo — Calculadora

// Haz clic en un operador

3. Funciones

Una función es un bloque de código reutilizable que realiza una tarea específica. Se define una vez y se puede ejecutar (invocar) múltiples veces.

Tres formas de declarar funciones

// ── 1. Declaración de función (function declaration) ──
// Se "sube" al inicio del scope (hoisting). Se puede llamar antes de declararse.
function saludar(nombre) {
  return `Hola, ${nombre}!`;
}
saludar("Ana");  // → "Hola, Ana!"


// ── 2. Expresión de función (function expression) ──
// Asignada a una variable. NO tiene hoisting.
const sumar = function(a, b) {
  return a + b;
};
sumar(3, 4);  // → 7


// ── 3. Arrow function (función flecha) ──
// Sintaxis más corta. No tiene su propio "this".
const multiplicar = (a, b) => a * b;
multiplicar(5, 6);  // → 30

// Si el cuerpo tiene varias líneas, necesita llaves y return
const calcularDescuento = (precio, porcentaje) => {
  const descuento = precio * (porcentaje / 100);
  return precio - descuento;
};

Parámetros y valores por defecto

// Parámetros con valor por defecto
function saludar(nombre = "Invitado", idioma = "es") {
  if (idioma === "es") return `Hola, ${nombre}!`;
  if (idioma === "en") return `Hello, ${nombre}!`;
}

saludar();            // → "Hola, Invitado!"
saludar("Ana");       // → "Hola, Ana!"
saludar("Bob", "en"); // → "Hello, Bob!"

// Rest parameters → recibe número variable de argumentos
function sumarTodo(...numeros) {
  return numeros.reduce((acc, n) => acc + n, 0);
}
sumarTodo(1, 2, 3, 4);  // → 10

Scope (Alcance)

// Variables GLOBALES → accesibles desde cualquier lugar
const global = "soy global";

function ejemplo() {
  // Variables LOCALES → solo dentro de la función
  const local = "solo existo aquí";
  console.log(global);  // ✅ puede leer la global
  console.log(local);   // ✅ puede leer la local
}

console.log(global);  // ✅ accesible
console.log(local);   // ❌ ReferenceError: local is not defined
✅ Arrow function concisa
// Una línea, retorno implícito
const doble = n => n * 2;
const esPar  = n => n % 2 === 0;

[1,2,3].map(doble); // [2,4,6]
❌ Sin parámetros nombrados
// Difícil de entender
const fn = (a,b,c) => a*b+c/2;

// Mejor así:
const calcular = (precio,cantidad,descuento) =>
  precio * cantidad + descuento / 2;

▶ Demo interactivo — Funciones

// Ingresa tu nombre y año de nacimiento

4. Estructuras de control

Las estructuras de control determinan el flujo de ejecución del programa: qué código se ejecuta y cuándo.

if / else if / else

const nota = 75;

if (nota >= 90) {
  console.log("Excelente");
} else if (nota >= 70) {
  console.log("Aprobado");     // ← se ejecuta este bloque
} else if (nota >= 60) {
  console.log("Suficiente");
} else {
  console.log("Reprobado");
}

Operador ternario

Versión compacta del if/else para una sola expresión:

// condición ? valor_si_true : valor_si_false
const mensaje = nota >= 70 ? "Aprobado" : "Reprobado";

// Equivale a:
let mensaje2;
if (nota >= 70) {
  mensaje2 = "Aprobado";
} else {
  mensaje2 = "Reprobado";
}

switch

const dia = "lunes";

switch (dia) {
  case "lunes":
  case "martes":
  case "miércoles":
  case "jueves":
  case "viernes":
    console.log("Día laboral");
    break;
  case "sábado":
  case "domingo":
    console.log("Fin de semana");
    break;
  default:
    console.log("Día desconocido");
}

Bucles (for, while, forEach)

// for clásico
for (let i = 0; i < 5; i++) {
  console.log(`Iteración ${i}`);
}

// for...of → recorrer arrays
const frutas = ["manzana", "pera", "uva"];
for (const fruta of frutas) {
  console.log(fruta);
}

// for...in → recorrer propiedades de objetos
const persona = { nombre: "Ana", edad: 22 };
for (const clave in persona) {
  console.log(`${clave}: ${persona[clave]}`);
}

// while
let contador = 0;
while (contador < 3) {
  console.log(contador);
  contador++;
}

▶ Demo interactivo — Clasificador de notas

// Ingresa una nota del 0 al 100

5. El DOM — Document Object Model

El DOM es la representación en memoria de la página HTML. JavaScript puede leer y modificar esta representación para cambiar lo que el usuario ve en tiempo real, sin recargar la página.

Analogía: Si HTML es el plano de una casa, el DOM es la casa real construida. Puedes modificar la casa (mover muebles, cambiar paredes) sin cambiar el plano original.

Árbol del DOM

document
<html>
<head>
<title> "Mi página"
<body>
<h1 id="titulo"> "Hola"
<p class="descripcion"> "Texto..."
<button id="btn"> "Clic"

Seleccionar elementos

// querySelector → primer elemento que coincide (CSS selector)
const titulo   = document.querySelector("#titulo");
const parrafo  = document.querySelector(".descripcion");
const boton    = document.querySelector("button");

// querySelectorAll → NodeList de TODOS los que coinciden
const items    = document.querySelectorAll("li");
const parrafos = document.querySelectorAll(".descripcion");

// Métodos clásicos (siguen siendo útiles)
const porId    = document.getElementById("titulo");
const porClase = document.getElementsByClassName("descripcion");

Modificar contenido, estilos y clases

const titulo = document.querySelector("#titulo");

// Contenido
titulo.textContent = "Nuevo título";   // solo texto, seguro
titulo.innerHTML   = "Título <em>cursiva</em>"; // puede incluir HTML

// Estilos en línea
titulo.style.color       = "red";
titulo.style.fontSize    = "2rem";
titulo.style.display     = "none";    // ocultar

// Atributos
titulo.setAttribute("data-id", "42");
titulo.getAttribute("id");             // → "titulo"

// Clases CSS (la forma recomendada)
titulo.classList.add("activo");       // agregar clase
titulo.classList.remove("activo");    // eliminar clase
titulo.classList.toggle("activo");    // alternar (si la tiene la quita, si no la agrega)
titulo.classList.contains("activo");  // → true/false

Crear y eliminar elementos

// Crear un elemento nuevo
const nuevoParrafo = document.createElement("p");
nuevoParrafo.textContent = "Este párrafo fue creado con JS";
nuevoParrafo.classList.add("parrafo-nuevo");

// Agregarlo al DOM
document.body.appendChild(nuevoParrafo);           // al final del body
document.querySelector("#lista").prepend(nuevoParrafo); // al inicio

// Eliminar un elemento
nuevoParrafo.remove();

// Recorrer una lista de elementos del DOM
document.querySelectorAll("li").forEach(item => {
  item.style.color = "green";
});

▶ Demo interactivo — Manipulación del DOM

Título modificable

La lista aparecerá aquí…

Haz clic en ✕ para eliminar un ítem individualmente.

6. Eventos

Los eventos son señales que el navegador genera cuando algo ocurre: un clic, una tecla presionada, el ratón moviéndose, el formulario enviado, la página cargada. JavaScript puede escuchar esos eventos y ejecutar código en respuesta.

addEventListener

// Sintaxis:
elemento.addEventListener('tipo-de-evento', funcionHandler);

// Ejemplo con función anónima
const boton = document.querySelector("#btn");
boton.addEventListener('click', () => {
  console.log("¡Botón presionado!");
});

// Ejemplo con función nombrada (recomendado para poder remover)
function manejarClic(event) {
  console.log("Clic en:", event.target);
}
boton.addEventListener('click', manejarClic);
boton.removeEventListener('click', manejarClic); // ← remover

El objeto event

const input = document.querySelector("input");

// keydown → qué tecla se presionó
input.addEventListener('keydown', (event) => {
  console.log(event.key);        // → "Enter", "a", "Shift"...
  console.log(event.code);       // → "KeyA", "Enter"...
  if (event.key === 'Enter') {
    console.log("¡Enter presionado!");
  }
});

// mousemove → posición del cursor
document.addEventListener('mousemove', (event) => {
  console.log(event.clientX, event.clientY);
});

// submit → prevenir recarga de página en formularios
formulario.addEventListener('submit', (event) => {
  event.preventDefault();  // ← MUY IMPORTANTE
  // procesar datos del formulario...
});

Tipos de eventos más comunes

CategoríaEventoCuándo se dispara
RatónclickAl hacer clic
RatóndblclickAl hacer doble clic
RatónmouseenterAl entrar el cursor al elemento
RatónmouseleaveAl salir el cursor del elemento
RatónmousemoveAl mover el cursor dentro
TecladokeydownAl presionar una tecla
TecladokeyupAl soltar una tecla
FormulariosubmitAl enviar el formulario
FormularioinputAl cambiar el valor de un input
FormulariochangeAl confirmar el cambio (blur)
Formulariofocus / blurAl recibir/perder foco
DocumentoDOMContentLoadedAl terminar de parsear el HTML
DocumentoscrollAl hacer scroll en la página

▶ Demo interactivo — Eventos

Interactúa con la caja de abajo. Registra varios tipos de evento.

Haz clic, doble clic, o mueve el cursor aquí
clics: 0
// Los eventos aparecerán aquí

Delegación de eventos

// En vez de agregar listener a CADA ítem de la lista...
// ← ineficiente si hay muchos ítems o si se agregan dinámicamente

// Escuchar en el CONTENEDOR PADRE → delegación
const lista = document.querySelector("#lista");
lista.addEventListener('click', (event) => {
  // event.target → el elemento exacto que recibió el clic
  if (event.target.matches("li")) {
    event.target.classList.toggle("completado");
  }
});
// Funciona para ítems presentes Y futuros ✅

7. Proyecto aplicado — Calculadora de propinas

Este proyecto combina todos los conceptos de la semana: variables y tipos, funciones con lógica de cálculo, manipulación del DOM para mostrar resultados, y eventos para reaccionar a la interacción del usuario.

Conceptos aplicados: variables const/let · funciones de cálculo · querySelector y manipulación de textContent · addEventListener en botones e inputs · classList.toggle/add/remove · operadores aritméticos · condicionales con if

JS

Calculadora de Propinas

Divide la cuenta fácilmente entre varias personas

2
Propina total
$0.00
Total con propina
$0.00
Por persona
$0.00

Código de la calculadora

// ── Variables de estado ──────────────────────────────
let porcentajePropina = 10;
let cantidadPersonas  = 2;

// ── Función principal de cálculo ─────────────────────
function calcularPropina() {
  const cuenta = parseFloat(
    document.querySelector("#py-cuenta").value
  ) || 0;

  const propina      = cuenta * (porcentajePropina / 100);
  const total        = cuenta + propina;
  const porPersona   = total / cantidadPersonas;

  // Actualizar el DOM con los resultados
  document.querySelector("#py-out-propina").textContent =
    `$${propina.toFixed(2)}`;
  document.querySelector("#py-out-total").textContent  =
    `$${total.toFixed(2)}`;
  document.querySelector("#py-out-persona").textContent =
    `$${porPersona.toFixed(2)}`;
}

// ── Eventos en los botones de propina ────────────────
document.querySelectorAll(".propina-btn").forEach(btn => {
  btn.addEventListener('click', () => {
    // Quitar clase activo de todos, ponerla en este
    document.querySelectorAll(".propina-btn")
      .forEach(b => b.classList.remove("activo"));
    btn.classList.add("activo");
    porcentajePropina = Number(btn.dataset.propina);
    calcularPropina();
  });
});

// ── Eventos en botones de personas ───────────────────
document.querySelector("#py-mas").addEventListener('click', () => {
  cantidadPersonas++;
  actualizarPersonas();
});
document.querySelector("#py-menos").addEventListener('click', () => {
  if (cantidadPersonas > 1) cantidadPersonas--;
  actualizarPersonas();
});