SEMANA 07
Variables, tipos de datos, funciones, manipulación del DOM y manejo de eventos.
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
Regla práctica: Usa const siempre. Cambia a let solo cuando necesites reasignar el valor. Nunca uses var en código nuevo.
JavaScript tiene 7 tipos primitivos. Los tipos se determinan automáticamente — no se declaran explícitamente.
// 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"
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."
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);
});
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"
Los operadores realizan operaciones sobre valores (operandos). Una expresión es cualquier fragmento de código que produce un valor.
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)
// == 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.
// && → 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)
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.
// ── 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 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
// 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
// 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]
// Difícil de entender
const fn = (a,b,c) => a*b+c/2;
// Mejor así:
const calcular = (precio,cantidad,descuento) =>
precio * cantidad + descuento / 2;
Las estructuras de control determinan el flujo de ejecución del programa: qué código se ejecuta y cuándo.
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");
}
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";
}
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");
}
// 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++;
}
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.
// 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");
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 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";
});
Título modificable
La lista aparecerá aquí…
Haz clic en ✕ para eliminar un ítem individualmente.
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.
// 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
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...
});
| Categoría | Evento | Cuándo se dispara |
|---|---|---|
| Ratón | click | Al hacer clic |
| Ratón | dblclick | Al hacer doble clic |
| Ratón | mouseenter | Al entrar el cursor al elemento |
| Ratón | mouseleave | Al salir el cursor del elemento |
| Ratón | mousemove | Al mover el cursor dentro |
| Teclado | keydown | Al presionar una tecla |
| Teclado | keyup | Al soltar una tecla |
| Formulario | submit | Al enviar el formulario |
| Formulario | input | Al cambiar el valor de un input |
| Formulario | change | Al confirmar el cambio (blur) |
| Formulario | focus / blur | Al recibir/perder foco |
| Documento | DOMContentLoaded | Al terminar de parsear el HTML |
| Documento | scroll | Al hacer scroll en la página |
Interactúa con la caja de abajo. Registra varios tipos de evento.
// 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 ✅
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
Divide la cuenta fácilmente entre varias personas
// ── 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();
});