1. Fundamentos Básicos
Incluir JavaScript en HTML
<!-- En el head (carga antes que el contenido) -->
<script src="miarchivo.js"></script>
<!-- Al final del body (recomendado, carga después del contenido) -->
<body>
<!-- Contenido HTML -->
<script src="miarchivo.js"></script>
</body>
<!-- JavaScript inline -->
<script>
// Tu código JavaScript aquí
</script>
Comentarios
// Comentario de una línea
/*
Comentario
de múltiples
líneas
*/
Declaración de Variables
// Variables modernas (recomendadas)
let edad = 25; // Variable que puede cambiar
const PI = 3.1416; // Constante (no puede cambiar)
// Variable antigua (evitar)
var nombre = "Juan"; // Tiene problemas de ámbito
Tipos de Datos
// Primitivos
let texto = "Hola mundo"; // String (cadena de texto)
let numero = 42; // Number (número)
let decimal = 3.14; // Number (decimal)
let esVerdad = true; // Boolean (booleano)
let nada = null; // Null (valor nulo)
let indefinido = undefined; // Undefined (valor no definido)
let simbolo = Symbol("descripción"); // Symbol (identificador único)
let bigInt = 9007199254740991n; // BigInt (números muy grandes)
// Objetos
let objeto = { nombre: "Ana", edad: 30 }; // Object (objeto)
let lista = [1, 2, 3, 4]; // Array (arreglo)
let fecha = new Date(); // Object (objeto fecha)
Verificar Tipos
typeof "Hola"; // "string"
typeof 42; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (esto es un error histórico de JS)
typeof {}; // "object"
typeof []; // "object" (los arrays son objetos en JS)
typeof function(){};// "function"
2. Operadores
Aritméticos
let a = 10;
let b = 3;
let suma = a + b; // 13
let resta = a - b; // 7
let multiplicacion = a * b; // 30
let division = a / b; // 3.333...
let modulo = a % b; // 1 (resto de división)
let exponente = a ** b; // 1000 (10 elevado a 3)
// Incremento y decremento
let c = 5;
c++; // Incrementa c en 1 (ahora c = 6)
c--; // Decrementa c en 1 (ahora c = 5)
// Operadores de asignación
let x = 10;
x += 5; // x = x + 5 (ahora x = 15)
x -= 3; // x = x - 3 (ahora x = 12)
x *= 2; // x = x * 2 (ahora x = 24)
x /= 4; // x = x / 4 (ahora x = 6)
x %= 4; // x = x % 4 (ahora x = 2)
Comparación
let a = 5;
let b = "5";
a == b; // true (compara valor, ignora tipo)
a === b; // false (compara valor Y tipo)
a != b; // false (distinto valor, ignora tipo)
a !== b; // true (distinto valor O tipo)
a > 3; // true
a >= 5; // true
a < 10; // true
a <= 4; // false
Lógicos
let x = 5;
let y = 10;
// AND lógico (&&): verdadero solo si ambas condiciones son verdaderas
(x > 0 && y > 0); // true
// OR lógico (||): verdadero si al menos una condición es verdadera
(x > 10 || y > 5); // true
// NOT lógico (!): invierte el valor
!(x > y); // true (porque x > y es falso)
3. Estructuras de Control
Condicionales
// if-else simple
if (edad >= 18) {
console.log("Eres mayor de edad");
} else {
console.log("Eres menor de edad");
}
// if-else if-else
if (nota >= 90) {
console.log("Sobresaliente");
} else if (nota >= 70) {
console.log("Notable");
} else if (nota >= 60) {
console.log("Aprobado");
} else {
console.log("Reprobado");
}
// Operador ternario (condición ? valor_si_verdadero : valor_si_falso)
let mensaje = (edad >= 18) ? "Mayor de edad" : "Menor de edad";
// switch
let dia = 2;
switch(dia) {
case 1:
console.log("Lunes");
break;
case 2:
console.log("Martes");
break;
// ... otros casos
default:
console.log("Día no válido");
}
Bucles (Loops)
// for
for (let i = 0; i < 5; i++) {
console.log(i); // Imprime 0, 1, 2, 3, 4
}
// for...of (para arrays y otros iterables)
let frutas = ["manzana", "naranja", "plátano"];
for (let fruta of frutas) {
console.log(fruta); // Imprime cada fruta
}
// for...in (para propiedades de objetos)
let persona = {nombre: "Juan", edad: 30};
for (let propiedad in persona) {
console.log(propiedad + ": " + persona[propiedad]);
}
// while
let contador = 0;
while (contador < 5) {
console.log(contador); // Imprime 0, 1, 2, 3, 4
contador++;
}
// do...while (se ejecuta al menos una vez)
let num = 0;
do {
console.log(num); // Imprime 0
num++;
} while (num < 1);
// break y continue
for (let i = 0; i < 10; i++) {
if (i === 3) continue; // Salta esta iteración
if (i === 7) break; // Sale del bucle
console.log(i); // Imprime 0, 1, 2, 4, 5, 6
}
4. Funciones
Declaración de Funciones
// Función declarativa
function saludar(nombre) {
return "Hola " + nombre;
}
// Función expresiva (asignada a variable)
const despedir = function(nombre) {
return "Adiós " + nombre;
};
// Función flecha (arrow function)
const multiplicar = (a, b) => a * b;
// Función con múltiples líneas
const calcularArea = (base, altura) => {
let resultado = base * altura / 2;
return resultado;
};
// Función con parámetros por defecto
function configurar(color = "azul", tamaño = "mediano") {
console.log(`Color: ${color}, Tamaño: ${tamaño}`);
}
Llamar Funciones
// Llamar a las funciones anteriores
saludar("María"); // "Hola María"
despedir("Juan"); // "Adiós Juan"
multiplicar(5, 3); // 15
calcularArea(10, 5); // 25
configurar(); // "Color: azul, Tamaño: mediano"
configurar("rojo"); // "Color: rojo, Tamaño: mediano"
configurar("verde", "grande"); // "Color: verde, Tamaño: grande"
Funciones Anónimas y Callbacks
// Función anónima (sin nombre)
setTimeout(function() {
console.log("Han pasado 3 segundos");
}, 3000);
// Callback (función que se pasa como argumento)
function procesar(numero, callback) {
let resultado = numero * 2;
callback(resultado);
}
procesar(5, function(resultado) {
console.log("El resultado es: " + resultado); // "El resultado es: 10"
});
5. Arrays (Arreglos)
Crear Arrays
// Declaración de arrays
let frutas = ["manzana", "pera", "plátano"];
let numeros = [1, 2, 3, 4, 5];
let mixto = [1, "dos", true, [4, 5]];
let nuevoArray = new Array(3); // [empty × 3]
// Acceder a elementos
let primerElemento = frutas[0]; // "manzana"
let ultimoElemento = frutas[frutas.length - 1]; // "plátano"
Métodos de Arrays
let animales = ["perro", "gato"];
// Modificar arrays
animales.push("conejo"); // Añade al final: ["perro", "gato", "conejo"]
animales.unshift("pájaro"); // Añade al inicio: ["pájaro", "perro", "gato", "conejo"]
let ultimo = animales.pop(); // Elimina y devuelve el último: "conejo"
let primero = animales.shift(); // Elimina y devuelve el primero: "pájaro"
// Arrays avanzados
let numeros = [1, 2, 3, 4, 5];
// map: transforma cada elemento
let dobles = numeros.map(num => num * 2); // [2, 4, 6, 8, 10]
// filter: filtra elementos que cumplen condición
let mayoresQue2 = numeros.filter(num => num > 2); // [3, 4, 5]
// reduce: reduce el array a un solo valor
let suma = numeros.reduce((total, num) => total + num, 0); // 15
// find: encuentra el primer elemento que cumple condición
let primeroMayor3 = numeros.find(num => num > 3); // 4
// some/every: comprueba si alguno/todos cumplen condición
let algunoMayor4 = numeros.some(num => num > 4); // true
let todosMenores10 = numeros.every(num => num < 10); // true
// sort: ordena el array (modifica el original)
numeros.sort((a, b) => b - a); // [5, 4, 3, 2, 1] (orden descendente)
Operaciones Comunes con Arrays
let datos = [3, 1, 4, 1, 5];
// Longitud del array
let longitud = datos.length; // 5
// Buscar un elemento
let indice = datos.indexOf(4); // 2
let ultimoIndice = datos.lastIndexOf(1); // 3
let incluye = datos.includes(5); // true
// Unir arrays
let array1 = [1, 2];
let array2 = [3, 4];
let unidos = array1.concat(array2); // [1, 2, 3, 4]
// Cortar un array (no modifica el original)
let subArray = datos.slice(1, 4); // [1, 4, 1]
// Eliminar/reemplazar elementos (modifica el original)
datos.splice(2, 1); // Elimina 1 elemento desde posición 2: [3, 1, 1, 5]
datos.splice(1, 0, 2); // Inserta 2 en posición 1: [3, 2, 1, 1, 5]
// Convertir array a string
let texto = datos.join(", "); // "3, 2, 1, 1, 5"
// Invertir array (modifica el original)
datos.reverse(); // [5, 1, 1, 2, 3]
6. Objetos
Crear y Acceder a Objetos
// Objeto literal
let persona = {
nombre: "Ana",
edad: 28,
ciudad: "Madrid",
hobbies: ["leer", "correr"],
direccion: {
calle: "Gran Vía",
numero: 42
}
};
// Acceder a propiedades
console.log(persona.nombre); // "Ana"
console.log(persona["edad"]); // 28
console.log(persona.hobbies[0]); // "leer"
console.log(persona.direccion.calle); // "Gran Vía"
// Añadir/modificar propiedades
persona.email = "ana@ejemplo.com"; // Añade nueva propiedad
persona.edad = 29; // Modifica propiedad existente
// Eliminar propiedad
delete persona.ciudad;
Métodos en Objetos
let calculadora = {
resultado: 0,
sumar: function(a, b) {
this.resultado = a + b;
return this.resultado;
},
// Sintaxis abreviada para métodos
restar(a, b) {
this.resultado = a - b;
return this.resultado;
}
};
calculadora.sumar(5, 3); // 8
calculadora.restar(10, 4); // 6
Constructores y Clases
// Constructor (forma antigua)
function Persona(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
this.saludar = function() {
return `Hola, soy ${this.nombre}`;
};
}
// Instanciar objetos
let persona1 = new Persona("Carlos", 35);
console.log(persona1.saludar()); // "Hola, soy Carlos"
// Clases (ES6+, forma moderna)
class Animal {
constructor(nombre, tipo) {
this.nombre = nombre;
this.tipo = tipo;
}
// Métodos
describir() {
return `${this.nombre} es un ${this.tipo}`;
}
// Getters y setters
get nombreEnMayusculas() {
return this.nombre.toUpperCase();
}
set cambiarNombre(nuevoNombre) {
this.nombre = nuevoNombre;
}
}
// Herencia
class Perro extends Animal {
constructor(nombre, raza) {
super(nombre, "perro");
this.raza = raza;
}
ladrar() {
return "¡Guau guau!";
}
}
let miPerro = new Perro("Max", "Labrador");
console.log(miPerro.describir()); // "Max es un perro"
console.log(miPerro.ladrar()); // "¡Guau guau!"
7. Manejo de Strings
Propiedades y Métodos Básicos
let texto = "JavaScript es genial";
// Longitud
console.log(texto.length); // 20
// Acceder a caracteres
console.log(texto[0]); // "J"
console.log(texto.charAt(4)); // "S"
// Buscar texto
console.log(texto.indexOf("Script")); // 4
console.log(texto.lastIndexOf("a")); // 15
console.log(texto.includes("genial")); // true
console.log(texto.startsWith("Java")); // true
console.log(texto.endsWith("genial")); // true
// Extraer partes
console.log(texto.slice(0, 10)); // "JavaScript"
console.log(texto.substring(11, 13)); // "es"
console.log(texto.substr(11, 2)); // "es" (obsoleto)
// Reemplazar
console.log(texto.replace("genial", "increíble")); // "JavaScript es increíble"
Transformación de Strings
let mensaje = "Hola Mundo";
// Mayúsculas y minúsculas
console.log(mensaje.toUpperCase()); // "HOLA MUNDO"
console.log(mensaje.toLowerCase()); // "hola mundo"
// Quitar espacios
let textoConEspacios = " texto con espacios ";
console.log(textoConEspacios.trim()); // "texto con espacios"
console.log(textoConEspacios.trimStart()); // "texto con espacios "
console.log(textoConEspacios.trimEnd()); // " texto con espacios"
// Dividir en array
console.log(mensaje.split(" ")); // ["Hola", "Mundo"]
// Repetir
console.log("Na".repeat(8) + " Batman!"); // "NaNaNaNaNaNaNaNa Batman!"
// Rellenar
console.log("5".padStart(3, "0")); // "005"
console.log("5".padEnd(3, "0")); // "500"
Plantillas Literales (Template Strings)
let nombre = "Laura";
let edad = 27;
// Concatenación tradicional
let mensaje1 = "Hola, soy " + nombre + " y tengo " + edad + " años.";
// Plantillas literales (con backticks `)
let mensaje2 = `Hola, soy ${nombre} y tengo ${edad} años.`;
// Plantillas multilínea
let plantilla = `
<div>
<h1>${nombre}</h1>
<p>Edad: ${edad}</p>
</div>~`;
8. Manejo de Errores
try…catch…finally
try {
// Código que puede generar un error
let resultado = funcionInexistente();
console.log(resultado);
} catch (error) {
// Manejo del error
console.error("Ocurrió un error:", error.message);
} finally {
// Se ejecuta siempre, haya error o no
console.log("Proceso finalizado");
}
Lanzar Errores Personalizados
function dividir(a, b) {
if (b === 0) {
throw new Error("No se puede dividir por cero");
}
return a / b;
}
try {
let resultado = dividir(10, 0);
} catch (error) {
console.error(error.message); // "No se puede dividir por cero"
}
9. Asincronía
setTimeout y setInterval
// Ejecutar una vez después de 2 segundos
setTimeout(() => {
console.log("Han pasado 2 segundos");
}, 2000);
// Ejecutar cada 1 segundo
let contador = 0;
let intervalo = setInterval(() => {
contador++;
console.log(`Han pasado ${contador} segundos`);
if (contador >= 5) {
clearInterval(intervalo); // Detener después de 5 segundos
}
}, 1000);
Callbacks
// Función con callback
function obtenerDatos(id, callback) {
setTimeout(() => {
let datos = { id: id, nombre: "Producto " + id };
callback(datos);
}, 1000);
}
obtenerDatos(123, (datos) => {
console.log("Datos recibidos:", datos);
});
Promesas
// Crear una promesa
function fetchDatos(url) {
return new Promise((resolve, reject) => {
// Simulación de petición
setTimeout(() => {
if (url.includes("datos")) {
resolve({ data: "Información obtenida" });
} else {
reject(new Error("URL no válida"));
}
}, 1000);
});
}
// Usar promesas
fetchDatos("api/datos")
.then(respuesta => {
console.log(respuesta.data); // "Información obtenida"
return "Proceso completado";
})
.then(mensaje => {
console.log(mensaje); // "Proceso completado"
})
.catch(error => {
console.error("Error:", error.message);
})
.finally(() => {
console.log("Proceso finalizado");
});
// Métodos Promise
Promise.all([
fetchDatos("api/datos1"),
fetchDatos("api/datos2")
]).then(resultados => {
// Se ejecuta cuando todas las promesas se resuelven
console.log(resultados); // [resultado1, resultado2]
});
Promise.race([
fetchDatos("api/datos1"),
fetchDatos("api/datos2")
]).then(primerResultado => {
// Se ejecuta cuando la primera promesa se resuelve
console.log(primerResultado);
});
Async/Await
// Función asíncrona
async function obtenerUsuario(id) {
try {
// await pausa la ejecución hasta que la promesa se resuelva
let respuesta = await fetch(`api/usuarios/${id}`);
if (!respuesta.ok) {
throw new Error("Error en la petición");
}
let datos = await respuesta.json();
return datos;
} catch (error) {
console.error("Error:", error.message);
throw error; // Re-lanzar para manejo externo
}
}
// Llamar a función async
async function main() {
try {
let usuario = await obtenerUsuario(1);
console.log(usuario);
} catch (error) {
console.error("Error en main:", error.message);
}
}
main();
10. DOM (Document Object Model)
Seleccionar Elementos
// Por ID
let elemento = document.getElementById("miId");
// Por clase
let elementos = document.getElementsByClassName("miClase");
// Por etiqueta
let parrafos = document.getElementsByTagName("p");
// Selectores CSS (devuelve el primero)
let selector = document.querySelector(".clase #id");
// Selectores CSS (devuelve todos)
let selectores = document.querySelectorAll("div > p");
Modificar Elementos
let elemento = document.getElementById("miElemento");
// Cambiar contenido
elemento.textContent = "Nuevo texto"; // Solo texto
elemento.innerHTML = "<strong>Texto con HTML</strong>"; // Incluyendo HTML
// Cambiar atributos
elemento.setAttribute("class", "destacado");
elemento.getAttribute("id"); // Obtiene valor de atributo
elemento.removeAttribute("title"); // Elimina atributo
// Cambiar estilos
elemento.style.color = "blue";
elemento.style.fontSize = "20px";
elemento.style.display = "none"; // Ocultar
// Clases CSS
elemento.classList.add("active");
elemento.classList.remove("disabled");
elemento.classList.toggle("visible"); // Alterna (añade/elimina)
elemento.classList.contains("active"); // true/false
Crear y Eliminar Elementos
// Crear elemento
let nuevoDiv = document.createElement("div");
nuevoDiv.textContent = "Nuevo elemento";
nuevoDiv.className = "contenedor";
// Añadir al DOM
document.body.appendChild(nuevoDiv); // Al final
document.body.prepend(nuevoDiv); // Al principio
let referencia = document.getElementById("elementoReferencia");
document.body.insertBefore(nuevoDiv, referencia); // Antes de referencia
// Reemplazar
let reemplazo = document.createElement("p");
reemplazo.textContent = "Elemento de reemplazo";
referencia.parentNode.replaceChild(reemplazo, referencia);
// Eliminar
let elementoAEliminar = document.getElementById("obsoleto");
elementoAEliminar.remove(); // Método moderno
// O de forma antigua
elementoAEliminar.parentNode.removeChild(elementoAEliminar);
Eventos
let boton = document.getElementById("miBoton");
// Método simple
boton.onclick = function() {
alert("Botón clickeado");
};
// Método recomendado (permite múltiples manejadores)
boton.addEventListener("click", function(evento) {
alert("Clickeado mediante listener");
console.log(evento); // Objeto de evento
});
// Eliminar manejador (debe ser la misma función)
function manejador() {
console.log("Manejador");
}
boton.addEventListener("click", manejador);
boton.removeEventListener("click", manejador);
// Prevenir comportamiento predeterminado
let enlace = document.querySelector("a");
enlace.addEventListener("click", function(e) {
e.preventDefault(); // Evita navegación
console.log("Enlace clickeado");
});
// Propagación de eventos
let padre = document.getElementById("padre");
let hijo = document.getElementById("hijo");
// Fase de captura (del documento hacia el elemento)
padre.addEventListener("click", e => console.log("Captura padre"), true);
// Fase de burbujeo (del elemento hacia el documento, por defecto)
hijo.addEventListener("click", e => {
e.stopPropagation(); // Detiene la propagación
console.log("Click hijo");
});
11. Almacenamiento Local
localStorage y sessionStorage
// localStorage (permanece hasta que se borre)
localStorage.setItem("usuario", "Juan");
let usuario = localStorage.getItem("usuario"); // "Juan"
localStorage.removeItem("usuario");
localStorage.clear(); // Borra todo
// sessionStorage (dura hasta cerrar pestaña/navegador)
sessionStorage.setItem("token", "abc123");
let token = sessionStorage.getItem("token");
sessionStorage.removeItem("token");
sessionStorage.clear();
// Almacenar objetos (convertir a JSON)
let configuracion = { tema: "oscuro", notificaciones: true };
localStorage.setItem("config", JSON.stringify(configuracion));
// Recuperar objetos
let configGuardada = JSON.parse(localStorage.getItem("config"));
12. Módulos JavaScript (ES6+)
Exportar
// archivo: matematicas.js
// Exportación con nombre
export function sumar(a, b) {
return a + b;
}
export function restar(a, b) {
return a - b;
}
// Exportación por defecto (solo una por archivo)
export default function multiplicar(a, b) {
return a * b;
}
// Exportar constantes
export const PI = 3.1416;
###
// archivo: app.js
// Importar lo exportado por defecto
import multiplicar from './matematicas.js';
// Importar exportaciones con nombre
import { sumar, restar, PI } from './matematicas.js';
// Importar con alias
import { sumar as suma, restar as resta } from './matematicas.js';
// Importar todo en un objeto
import * as matematicas from './matematicas.js';
console.log(matematicas.sumar(5, 3));
console.log(matematicas.PI);
// Importar en HTML
<script type="module" src="app.js"></script>
13. APIs Web Comunes
Fetch API (para peticiones HTTP)
// GET request básico
fetch('https://api.ejemplo.com/datos')
.then(response => {
if (!response.ok) {
throw new Error('Error en la respuesta');
}
return response.json(); // Parsea JSON
})
.then(datos => {
console.log(datos);
})
.catch(error => {
console.error('Error:', error);
});
// POST request
fetch('https://api.ejemplo.com/crear', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
nombre: 'Producto nuevo',
precio: 29.99
})
})
.then(response => response.json())
.then(resultado => console.log(resultado));
// Con async/await
async function obtenerDatos() {
try {
let respuesta = await fetch('https://api.ejemplo.com/datos');
if (!respuesta.ok) throw new Error('Error en la respuesta');
let datos = await respuesta.json();
return datos;
} catch (error) {
console.error('Error:', error);
}
}
JSON
// Convertir objeto a string JSON
let objeto = { nombre: "Juan", edad: 30 };
let jsonString = JSON.stringify(objeto);
console.log(jsonString); // '{"nombre":"Juan","edad":30}'
// Convertir string JSON a objeto
let jsonRecibido = '{"producto":"Laptop","precio":999.99}';
let objetoJS = JSON.parse(jsonRecibido);
console.log(objetoJS.producto); // "Laptop"
14. Conceptos Avanzados
Closures (Cierres)
function crearContador() {
let contador = 0;
// Esta función interna tiene acceso a 'contador'
return function() {
contador++;
return contador;
};
}
let incrementar = crearContador();
console.log(incrementar()); // 1
console.log(incrementar()); // 2
console.log(incrementar()); // 3
Destructuring (Desestructuración)
// Arrays
let colores = ["rojo", "verde", "azul"];
let [primario, secundario, terciario] = colores;
console.log(primario); // "rojo"
// Con valores por defecto
let [a, b, c, d = "negro"] = colores;
console.log(d); // "negro"
// Objetos
let persona = { nombre: "Ana", edad: 28, ciudad: "Madrid" };
let { nombre, edad } = persona;
console.log(nombre); // "Ana"
// Renombrar propiedades
let { nombre: nombreCompleto, ciudad: ubicacion = "Desconocida" } = persona;
console.log(nombreCompleto); // "Ana"
console.log(ubicacion); // "Madrid"
// Destructuring en parámetros de función
function mostrarInfo({ nombre, edad }) {
console.log(`${nombre} tiene ${edad} años`);
}
mostrarInfo(persona); // "Ana tiene 28 años"
Spread Operator y Rest Parameters
// Spread en arrays (...)
let numeros = [1, 2, 3];
let masNumeros = [...numeros, 4, 5]; // [1, 2, 3, 4, 5]
// Copiar array
let copiaNums = [...numeros]; // Crea una copia independiente
// Spread en objetos
let datosBase = { id: 1, nombre: "Producto" };
let producto = {
...datosBase,
precio: 99.99,
disponible: true
};
// Rest parameters (resto de parámetros)
function sumar(primero, ...resto) {
return resto.reduce((total, num) => total + num, primero);
}
console.log(sumar(1, 2, 3, 4)); // 10
this y Contexto
// 'this' en métodos de objeto
let usuario = {
nombre: "Luis",
saludar() {
console.log(`Hola, soy ${this.nombre}`);
}
};
usuario.saludar(); // "Hola, soy Luis"
// Problema con 'this' en callbacks
let usuario2 = {
nombre: "Ana",
saludarDespues() {
setTimeout(function() {
console.log(`Hola, soy ${this.nombre}`); // 'this' no refiere a usuario2
}, 1000);
}
};
// Soluciones:
// 1. Usar arrow function
let usuario3 = {
nombre: "Carlos",
saludarDespues() {
setTimeout(() => {
console.log(`Hola, soy ${this.nombre}`); // 'this' se mantiene
}, 1000);
}
};
// 2. Usar bind
let usuario4 = {
nombre: "Elena",
saludarDespues() {
setTimeout(function() {
console.log(`Hola, soy ${this.nombre}`);
}.bind(this), 1000);
}
};
// 3. Guardar referencia
let usuario5 = {
nombre: "Pablo",
saludarDespues() {
let self = this;
setTimeout(function() {
console.log(`Hola, soy ${self.nombre}`);
}, 1000);
}
};
Map, Set, WeakMap, WeakSet
// Map: colección de pares clave-valor
let mapa = new Map();
mapa.set("nombre", "Ana");
mapa.set(1, "número uno");
mapa.set(true, "booleano");
console.log(mapa.get("nombre")); // "Ana"
console.log(mapa.has(1)); // true
console.log(mapa.size); // 3
mapa.delete(true);
mapa.clear(); // Vacía el mapa
// Set: colección de valores únicos
let conjunto = new Set([1, 2, 3, 3, 4]); // {1, 2, 3, 4}
conjunto.add(5);
conjunto.add(1); // No se duplica
console.log(conjunto.has(3)); // true
console.log(conjunto.size); // 5
conjunto.delete(4);
// WeakMap: claves deben ser objetos, no previene garbage collection
let weakMap = new WeakMap();
let obj1 = {};
let obj2 = {};
weakMap.set(obj1, "valor1");
weakMap.set(obj2, "valor2");
// WeakSet: solo almacena referencias débiles a objetos
let weakSet = new WeakSet();
weakSet.add(obj1);
console.log(weakSet.has(obj1)); // true
15. JavaScript Moderno (ES6+)
let y const
// var (evitar usar)
var x = 10;
if (true) {
var x = 20; // Modifica la x externa
}
console.log(x); // 20
// let (ámbito de bloque)
let y = 10;
if (true) {
let y = 20; // Nueva variable solo en este bloque
}
console.log(y); // 10
// const (constante, no reasignable)
const PI = 3.14;
// PI = 3.1416; // Error: no se puede reasignar
// Pero los objetos/arrays const sí pueden modificar su contenido
const persona = { nombre: "Juan" };
persona.nombre = "Luis"; // OK
persona.edad = 30; // OK
// persona = {}; // Error: no se puede reasignar
Arrow Functions
// Función tradicional
function sumar(a, b) {
return a + b;
}
// Arrow function equivalente
const sumarArrow = (a, b) => a + b;
// Con un parámetro (paréntesis opcionales)
const duplicar = x => x * 2;
// Sin parámetros
const saludar = () => "Hola mundo";
// Con cuerpo de función
const calcular = (a, b) => {
let resultado = a * b;
return resultado + 10;
};
// Diferencias con this
function FuncionTradicional() {
this.valor = 42;
setTimeout(function() {
// 'this' aquí se refiere a window o undefined
console.log(this.valor); // undefined
}, 1000);
}
function FuncionArrow() {
this.valor = 42;
setTimeout(() => {
// 'this' aquí se mantiene como el de FuncionArrow
console.log(this.valor); // 42
}, 1000);
}
Classes
// Definición de clase
class Persona {
// Constructor
constructor(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
this._privado = "valor"; // Convención para indicar "privado"
}
// Métodos
saludar() {
return `Hola, soy ${this.nombre}`;
}
// Getters y setters
get info() {
return `${this.nombre}, ${this.edad} años`;
}
set nuevoNombre(valor) {
if (valor.length > 2) {
this.nombre = valor;
}
}
// Métodos estáticos (de la clase, no de instancias)
static crear(datos) {
return new Persona(datos.nombre, datos.edad);
}
}
// Instanciar
let persona1 = new Persona("Ana", 28);
console.log(persona1.saludar()); // "Hola, soy Ana"
console.log(persona1.info); // "Ana, 28 años"
persona1.nuevoNombre = "María";
console.log(persona1.nombre); // "María"
// Usar método estático
let datos = { nombre: "Juan", edad: 30 };
let persona2 = Persona.crear(datos);
// Herencia
class Empleado extends Persona {
constructor(nombre, edad, puesto) {
super(nombre, edad); // Llama al constructor de la clase padre
this.puesto = puesto;
}
// Sobrescribir método
saludar() {
return `${super.saludar()} y trabajo como ${this.puesto}`;
}
}
let empleado1 = new Empleado("Carlos", 35, "Desarrollador");
console.log(empleado1.saludar()); // "Hola, soy Carlos y trabajo como Desarrollador"
Plantillas Literales (Template Literals)
let nombre = "María";
let edad = 25;
// Concatenación tradicional
let mensaje1 = "Hola, me llamo " + nombre + " y tengo " + edad + " años.";
// Plantilla literal
let mensaje2 = `Hola, me llamo ${nombre} y tengo ${edad} años.`;
// Expresiones en plantillas
let a = 5;
let b = 10;
console.log(`La suma es: ${a + b} y la multiplicación es: ${a * b}`);
// Plantillas multilínea
let html = `
<div>
<h1>${nombre}</h1>
<p>Edad: ${edad}</p>
</div>`;
Valores por Defecto en Parámetros
// Forma antigua
function saludar(nombre) {
nombre = nombre || "Invitado";
return "Hola " + nombre;
}
// Con valores por defecto
function saludarES6(nombre = "Invitado", mensaje = "Bienvenido") {
return `${mensaje}, ${nombre}`;
}
saludarES6(); // "Bienvenido, Invitado"
saludarES6("Juan"); // "Bienvenido, Juan"
saludarES6("María", "Hola"); // "Hola, María"
Opcional Chaining y Nullish Coalescing
// Encadenamiento opcional (?.)
let usuario = {
detalles: {
// dirección no está definida
}
};
// Sin encadenamiento opcional
// let calle = usuario.detalles.direccion.calle; // Error
// Con encadenamiento opcional
let calle = usuario.detalles?.direccion?.calle; // undefined (sin error)
// En funciones
let fn = null;
fn?.(); // No hace nada, sin error
// Operador de fusión nula (??)
// Devuelve el valor a la derecha solo si el izquierdo es null o undefined
let nombre = null;
let nombreMostrar = nombre ?? "Sin nombre"; // "Sin nombre"
// Diferencia con OR lógico
let conteo = 0; // falsy pero válido
let resultado1 = conteo || 10; // 10 (porque 0 es falsy)
let resultado2 = conteo ?? 10; // 0 (porque 0 no es null/undefined)
Iteradores y Generadores
// Iteradores personalizados
let contador = {
[Symbol.iterator]() {
let valor = 0;
return {
next() {
if (valor < 3) {
return { value: valor++, done: false };
}
return { done: true };
}
};
}
};
for (let num of contador) {
console.log(num); // 0, 1, 2
}
// Generadores (funciones que pueden pausar/reanudar)
function* generadorSimple() {
yield 1;
yield 2;
yield 3;
}
let generador = generadorSimple();
console.log(generador.next()); // { value: 1, done: false }
console.log(generador.next()); // { value: 2, done: false }
console.log(generador.next()); // { value: 3, done: false }
console.log(generador.next()); // { value: undefined, done: true }
// Generador con bucle
function* generadorRango(inicio, fin) {
for (let i = inicio; i <= fin; i++) {
yield i;
}
}
for (let num of generadorRango(5, 10)) {
console.log(num); // 5, 6, 7, 8, 9, 10
}
16. Web APIs
localStorage y sessionStorage
// localStorage (permanece incluso al cerrar navegador)
localStorage.setItem("tema", "oscuro");
let tema = localStorage.getItem("tema"); // "oscuro"
localStorage.removeItem("tema");
localStorage.clear(); // Borra todo
// sessionStorage (dura la sesión actual)
sessionStorage.setItem("token", "abc123");
let token = sessionStorage.getItem("token");
sessionStorage.removeItem("token");
// Guardar objetos (convertir a JSON)
let configuracion = { idioma: "es", notificaciones: true };
localStorage.setItem("config", JSON.stringify(configuracion));
// Recuperar objetos
let configGuardada = JSON.parse(localStorage.getItem("config"));
Geolocalización
// Obtener ubicación actual
navigator.geolocation.getCurrentPosition(
// Éxito
(posicion) => {
console.log(`Latitud: ${posicion.coords.latitude}`);
console.log(`Longitud: ${posicion.coords.longitude}`);
console.log(`Precisión: ${posicion.coords.accuracy} metros`);
},
// Error
(error) => {
console.error(`Error (${error.code}): ${error.message}`);
},
// Opciones
{
enableHighAccuracy: true, // Mayor precisión (consume más batería)
timeout: 5000, // Tiempo máximo (ms)
maximumAge: 0 // No usar caché
}
);
// Seguimiento continuo
let watchId = navigator.geolocation.watchPosition(
(posicion) => console.log(posicion.coords.latitude),
(error) => console.error(error)
);
// Detener seguimiento
navigator.geolocation.clearWatch(watchId);
Notificaciones
// Pedir permiso
Notification.requestPermission().then(permiso => {
if (permiso === 'granted') {
console.log("Permiso concedido");
}
});
// Mostrar notificación
function mostrarNotificacion() {
if (Notification.permission === 'granted') {
let notificacion = new Notification('Nuevo mensaje', {
body: 'Has recibido un mensaje nuevo',
icon: '/icono.png'
});
// Eventos
notificacion.onclick = () => {
window.focus();
notificacion.close();
};
// Cerrar automáticamente
setTimeout(() => notificacion.close(), 5000);
}
}
Canvas
// Obtener contexto
let canvas = document.getElementById('miCanvas');
let ctx = canvas.getContext('2d');
// Dibujar rectángulo
ctx.fillStyle = 'blue';
ctx.fillRect(10, 10, 100, 50); // x, y, ancho, alto
// Dibujar línea
ctx.beginPath();
ctx.moveTo(10, 100); // Punto inicial
ctx.lineTo(110, 100); // Punto final
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
ctx.stroke();
// Dibujar círculo
ctx.beginPath();
ctx.arc(60, 200, 50, 0, 2 * Math.PI); // x, y, radio, ángulo inicio, ángulo fin
ctx.fillStyle = 'green';
ctx.fill();
ctx.strokeStyle = 'black';
ctx.stroke();
// Texto
ctx.font = '24px Arial';
ctx.fillStyle = 'black';
ctx.fillText('Hola Canvas', 20, 300);
Drag and Drop
// Elemento arrastrable
let elemento = document.getElementById('arrastrable');
elemento.draggable = true; // Hacer elemento arrastrable
elemento.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', e.target.id);
e.target.classList.add('arrastrando');
});
elemento.addEventListener('dragend', (e) => {
e.target.classList.remove('arrastrando');
});
// Zona de destino
let destino = document.getElementById('destino');
destino.addEventListener('dragover', (e) => {
e.preventDefault(); // Necesario para permitir soltar
destino.classList.add('hover');
});
destino.addEventListener('dragleave', () => {
destino.classList.remove('hover');
});
destino.addEventListener('drop', (e) => {
e.preventDefault();
destino.classList.remove('hover');
let id = e.dataTransfer.getData('text/plain');
let elementoArrastrado = document.getElementById(id);
destino.appendChild(elementoArrastrado);
});
17. Testing en JavaScript
Jest (Framework de Testing)
// Archivo a testear: math.js
export function sumar(a, b) {
return a + b;
}
export function restar(a, b) {
return a - b;
}
// Archivo de test: math.test.js
import { sumar, restar } from './math';
// Tests simples
test('sumar 1 + 2 es igual a 3', () => {
expect(sumar(1, 2)).toBe(3);
});
test('restar 5 - 2 es igual a 3', () => {
expect(restar(5, 2)).toBe(3);
});
// Con describe para agrupar
describe('Funciones matemáticas', () => {
test('sumar funciona con números negativos', () => {
expect(sumar(-1, -2)).toBe(-3);
});
test('restar funciona con decimales', () => {
expect(restar(5.5, 2.2)).toBeCloseTo(3.3);
});
});
// Matchers comunes
test('Ejemplos de matchers', () => {
expect(2 + 2).toBe(4); // Igualdad exacta
expect({a: 1}).toEqual({a: 1}); // Igualdad de estructura
expect(null).toBeNull(); // Es null
expect(undefined).toBeUndefined(); // Es undefined
expect(true).toBeTruthy(); // Es truthy
expect(false).toBeFalsy(); // Es falsy
expect([1, 2, 3]).toContain(2); // Contiene elemento
expect(5).toBeGreaterThan(3); // Mayor que
expect(() => { throw new Error() }).toThrow(); // Lanza error
});
Mocks y Spies
// Función a testear
function llamarCallback(callback) {
callback('datos');
}
// Test con mock
test('callback es llamado con datos', () => {
const mockCallback = jest.fn();
llamarCallback(mockCallback);
expect(mockCallback).toHaveBeenCalled();
expect(mockCallback).toHaveBeenCalledWith('datos');
expect(mockCallback).toHaveBeenCalledTimes(1);
});
// Mocks más complejos
test('mock personalizado', () => {
const mockFn = jest.fn()
.mockReturnValueOnce(10)
.mockReturnValueOnce('hello')
.mockReturnValue(true);
console.log(mockFn(), mockFn(), mockFn(), mockFn());
// 10, 'hello', true, true
});
// Spies (espías)
import { objeto } from './module';
test('espiar un método', () => {
const spy = jest.spyOn(objeto, 'metodo');
objeto.metodo('test');
expect(spy).toHaveBeenCalledWith('test');
// Restaurar la implementación original
spy.mockRestore();
});
18. Depuración (Debugging)
Console
// Métodos básicos
console.log("Mensaje informativo");
console.info("Información");
console.warn("Advertencia");
console.error("Error");
// Agrupación
console.group("Grupo 1");
console.log("Mensaje dentro del grupo");
console.log("Otro mensaje");
console.groupEnd();
// Tabla
console.table([
{ nombre: "Juan", edad: 30 },
{ nombre: "Ana", edad: 25 }
]);
// Tiempo
console.time("Operación");
// ... código a medir
console.timeEnd("Operación"); // "Operación: 25.123ms"
// Seguimiento de pila
console.trace("Seguimiento");
// Estilizar consola
console.log("%cTexto estilizado", "color: blue; font-size: 20px");
Debugger
function calcular() {
let a = 10;
let b = 5;
debugger; // El navegador pausa aquí cuando las herramientas de desarrollo están abiertas
let resultado = a * b;
return resultado;
}
19. Rendimiento y Optimización
Performance API
// Medir tiempo de ejecución
performance.mark("inicio");
// Código a medir
for (let i = 0; i < 1000000; i++) {
// Operación costosa
}
performance.mark("fin");
performance.measure("Duración", "inicio", "fin");
const medidas = performance.getEntriesByName("Duración");
console.log(`Duración: ${medidas[0].duration}ms`);
// Limpiar marcas
performance.clearMarks();
performance.clearMeasures();
Web Workers
// En el archivo principal.js
if (window.Worker) {
// Crear worker
const worker = new Worker('worker.js');
// Enviar mensaje al worker
worker.postMessage({
comando: 'calcular',
datos: [1, 2, 3, 4, 5]
});
// Recibir resultados
worker.onmessage = function(e) {
console.log('Resultado recibido del worker:', e.data);
};
// Manejar errores
worker.onerror = function(error) {
console.error('Error en el worker', error);
};
// Terminar worker cuando ya no se necesite
// worker.terminate();
}
// En el archivo worker.js
self.onmessage = function(e) {
const { comando, datos } = e.data;
if (comando === 'calcular') {
// Hacer cálculos intensivos sin bloquear el hilo principal
const resultado = datos.map(x => x * x).reduce((a, b) => a + b, 0);
// Devolver resultado
self.postMessage(resultado);
}
};
20. JavaScript de Servidor (Node.js)
Módulos en Node.js
// Exportar (archivo: utils.js)
const PI = 3.14159;
function sumar(a, b) {
return a + b;
}
module.exports = {
PI,
sumar,
restar: function(a, b) {
return a - b;
}
};
// Importar (archivo: app.js)
const utils = require('./utils');
console.log(utils.PI); // 3.14159
console.log(utils.sumar(2, 3)); // 5
// Desestructuración al importar
const { PI, restar } = require('./utils');
console.log(PI); // 3.14159
console.log(restar(10, 5)); // 5
npm y package.json
// Iniciar proyecto
// npm init
// Instalar paquete
// npm install express
// package.json ejemplo
{
"name": "mi-proyecto",
"version": "1.0.0",
"description": "Descripción del proyecto",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest"
},
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.15",
"jest": "^27.5.1"
}
}
// Usar paquetes
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hola mundo');
});
app.listen(3000, () => {
console.log('Servidor en puerto 3000');
});
Sistema de archivos (fs)
const fs = require('fs');
// Operaciones síncronas (bloqueantes)
try {
// Leer archivo
const datos = fs.readFileSync('archivo.txt', 'utf8');
console.log(datos);
// Escribir archivo
fs.writeFileSync('nuevo.txt', 'Contenido nuevo');
// Comprobar si existe
const existe = fs.existsSync('archivo.txt');
} catch (error) {
console.error('Error:', error);
}
// Operaciones asíncronas (no bloqueantes)
fs.readFile('archivo.txt', 'utf8', (error, datos) => {
if (error) {
console.error('Error al leer:', error);
return;
}
console.log(datos);
});
fs.writeFile('nuevo.txt', 'Contenido nuevo', (error) => {
if (error) {
console.error('Error al escribir:', error);
}
});
// Con promesas
const fsPromises = require('fs').promises;
async function manejarArchivos() {
try {
const datos = await fsPromises.readFile('archivo.txt', 'utf8');
console.log(datos);
await fsPromises.writeFile('nuevo.txt', 'Contenido con promesas');
console.log('Archivo escrito');
} catch (error) {
console.error('Error:', error);
}
}