Programación · n.º 1 entre los lenguajes más usados

Aprende JavaScript desde cero

El lenguaje de la web: da vida a las páginas y también funciona en servidores.

  • 15 lecciones
  • 19 ejercicios interactivos
  • 26 conceptos clave
  • 62 % lo usa*

Qué es JavaScript y para qué sirve

JavaScript es el único lenguaje que entienden todos los navegadores, así que es el que hace que una web reaccione cuando pulsas un botón o rellenas un formulario. Con Node.js también se usa para crear servidores y herramientas. No necesitas instalar nada para empezar: la consola del navegador ya lo ejecuta.

  • Páginas web interactivas
  • Servidores con Node.js
  • Aplicaciones de escritorio y móvil

Para empezar: Abre la consola del navegador (F12, pestaña «Consola») y escribe el código de los ejemplos.

Nivel 1 Básico

Lección 1 · Básico

Tu primer programa

Un programa es una lista de instrucciones que el ordenador ejecuta en orden, de arriba abajo. En JavaScript, console.log() muestra en la consola lo que pongas entre los paréntesis: un texto entre comillas o el resultado de una operación.

Cada instrucción suele terminar en punto y coma. Lo que va detrás de // es un comentario: el ordenador lo ignora y sirve para explicar el código a quien lo lea.

Ejemplo práctico
// Muestra un saludo y el resultado de una suma
console.log("¡Hola, mundo!");
console.log(2 + 3); // 5

Ejercicio

Completa la instrucción para que muestre «Hola» en la consola.

console.("Hola");
Ver la solución

Respuesta: log. console.log() escribe en la consola lo que le pases.

Lección 2 · Básico

Variables y tipos de datos

Una variable es un nombre que guarda un valor para usarlo después. Con const declaras una que no vas a reasignar y con let una que sí puede cambiar. La antigua var se sigue entendiendo, pero hoy se prefieren las otras dos.

Los valores tienen un tipo: texto (string), número (number), verdadero o falso (boolean), y también undefined y null para «sin valor». El operador typeof te dice de qué tipo es algo.

Ejemplo práctico
const nombre = "Ana";   // texto
let edad = 30;          // número
edad = edad + 1;        // let permite cambiarla
const socia = true;     // booleano

console.log(nombre, edad);   // Ana 31
console.log(typeof edad);    // "number"

Ejercicio

Vas a guardar tu fecha de nacimiento y nunca cambiará. ¿Qué palabra usas?

Ver la solución

Respuesta: const. const impide reasignar la variable por error; let es para valores que van a cambiar.

Lección 3 · Básico

Condiciones: tomar decisiones

Con if el programa ejecuta un bloque solo si se cumple una condición, y con else indicas qué hacer si no. Para comparar se usan === (igual), !== (distinto), <, >, <= y >=.

Usa siempre === en lugar de ==: el doble igual convierte los tipos antes de comparar y da resultados sorprendentes, como que "5" == 5 sea verdadero.

Ejemplo práctico
const edad = 17;

if (edad >= 18) {
  console.log("Puedes votar");
} else {
  console.log("Aún no puedes votar");
}

console.log("5" === 5); // false: texto y número no son lo mismo

Ejercicio

¿Qué muestra console.log("5" === 5)?

Ver la solución

Respuesta: false. === compara también el tipo: un texto nunca es estrictamente igual a un número.

Encuentra los errores

La función puedeVotar(edad) debería devolver true (verdadero, sin comillas) si la persona tiene 18 años o más, y false si no. Tiene 2 errores: marca las líneas que fallan.

Ver la solución
  • Línea 2: Un solo = asigna: cambia edad a 18 y la condición siempre se cumple. Para comparar se usa ===. Corrección: if (edad === 18) {
  • Línea 6: "true" entre comillas es un texto, no el valor booleano true. Corrección: return true;

Lección 4 · Básico

Arrays y bucles

Un array es una lista ordenada de valores entre corchetes. Cada elemento tiene una posición que empieza en 0, y length te dice cuántos hay. Con push() añades uno al final.

Un bucle repite un bloque de código. for...of recorre los elementos de un array uno a uno, sin que tengas que llevar la cuenta de las posiciones.

Ejemplo práctico
const frutas = ["manzana", "pera"];
frutas.push("naranja");

console.log(frutas[0]);      // "manzana" (la posición 0 es la primera)
console.log(frutas.length);  // 3

for (const fruta of frutas) {
  console.log("Me gusta la " + fruta);
}

Ejercicio

Completa el bucle que recorre todas las frutas.

for (const fruta  frutas) {
  console.log(fruta);
}
Ver la solución

Respuesta: of. for (const x of lista) toma cada elemento de la lista por turno.

Escribe el código

Escribe la función sumarTodo(numeros): recibe un array de números y devuelve su suma. Hazlo con un bucle for y una variable que vaya acumulando el total.

Tab escribe una sangría; para salir del editor con el teclado, pulsa Esc y luego Tab. Ctrl + Intro corrige.

Ver la solución
function sumarTodo(numeros) {
  let total = 0;
  for (const n of numeros) {
    total += n;
  }
  return total;
}

Empieza con total = 0, suma cada número dentro del bucle y devuelve el total al final. Con un array vacío el bucle no se ejecuta y la función devuelve 0.

Nivel 2 Intermedio

Lección 5 · Intermedio

Funciones

Una función agrupa código con un nombre para reutilizarlo. Recibe datos (parámetros) y puede devolver un resultado con return. Así no repites la misma operación en varios sitios.

Además de function, existe la sintaxis de flecha =>, más corta, muy usada para funciones pequeñas.

Ejemplo práctico
function saludar(nombre) {
  return "Hola, " + nombre;
}

// La misma idea con una función flecha
const conIva = (precio) => precio * 1.21;

console.log(saludar("Luis")); // "Hola, Luis"
console.log(conIva(100));     // 121

Ejercicio

Con const conIva = (precio) => precio * 1.21;, ¿qué devuelve conIva(200)?

Ver la solución

Respuesta: 242. 200 × 1,21 = 242. La función multiplica el precio por 1,21 y lo devuelve.

Escribe el código

Escribe la función fizzBuzz(n): devuelve "FizzBuzz" si n es múltiplo de 3 y de 5, "Fizz" si solo lo es de 3, "Buzz" si solo lo es de 5 y, en otro caso, el propio número convertido en texto (String(n)).

Tab escribe una sangría; para salir del editor con el teclado, pulsa Esc y luego Tab. Ctrl + Intro corrige.

Ver la solución
function fizzBuzz(n) {
  if (n % 15 === 0) return "FizzBuzz";
  if (n % 3 === 0) return "Fizz";
  if (n % 5 === 0) return "Buzz";
  return String(n);
}

El orden importa: si se comprueba antes el 3, el 15 devolvería «Fizz». El operador % da el resto de la división: si es 0, el número es múltiplo.

Lección 6 · Intermedio

Objetos y JSON

Un objeto agrupa datos relacionados en pares clave–valor entre llaves. Accedes a cada valor con un punto (usuario.nombre) y puedes añadir o cambiar propiedades en cualquier momento.

JSON es un formato de texto basado en esta misma forma de escribir objetos y es el que usan casi todas las APIs. JSON.stringify() convierte un objeto en texto y JSON.parse() hace lo contrario.

Ejemplo práctico
const usuario = { nombre: "Eva", edad: 28, ciudad: "Sevilla" };
usuario.edad = 29;
console.log(usuario.nombre); // "Eva"

const texto = JSON.stringify(usuario);
console.log(texto); // {"nombre":"Eva","edad":29,"ciudad":"Sevilla"}

const copia = JSON.parse(texto);
console.log(copia.ciudad); // "Sevilla"

Ejercicio

Completa la línea que convierte el texto JSON en un objeto.

const datos = JSON.(texto);
Ver la solución

Respuesta: parse. JSON.parse() lee un texto JSON y devuelve el objeto equivalente.

Lección 7 · Intermedio

Recorrer listas con map, filter y reduce

Los arrays traen métodos que reciben una función y la aplican a cada elemento. filter() se queda con los que cumplen una condición, map() transforma cada uno y reduce() los combina en un solo valor, como una suma.

Estos métodos no modifican el array original: devuelven uno nuevo. Así el código es más fácil de seguir que con un bucle que va cambiando variables.

Ejemplo práctico
const compra = [
  { producto: "pan", precio: 1.2 },
  { producto: "aceite", precio: 7.5 },
  { producto: "leche", precio: 0.9 },
];

const baratos = compra.filter((p) => p.precio < 2);
const nombres = baratos.map((p) => p.producto);
const total = compra.reduce((suma, p) => suma + p.precio, 0);

console.log(nombres);          // ["pan", "leche"]
console.log(total.toFixed(2)); // "9.60"

Ejercicio

Quieres quedarte solo con los productos que cuestan más de 5 €. ¿Qué método usas?

Ver la solución

Respuesta: filter. filter() devuelve los elementos para los que la función devuelve verdadero.

Encuentra los errores

Este código debería quedarse con los precios de más de 20 €, aplicarles un 10 % de descuento y sumarlos (el resultado correcto es 58.5). Tiene 2 errores.

Ver la solución
  • Línea 4: Con llaves { } la función flecha necesita return; sin él devuelve undefined y filter descarta todos los precios. Corrección: const caros = precios.filter((p) => p > 20);
  • Línea 5: Multiplicar por 0.1 da el 10 % del precio, no el precio rebajado. Con un 10 % de descuento queda el 90 %: p * 0.9. Corrección: const rebajados = caros.map((p) => p * 0.9);

Nivel 3 Avanzado

Lección 8 · Avanzado

El DOM: cambiar la página

El DOM es la representación de la página que el navegador pone a disposición de JavaScript. Con document.querySelector() buscas un elemento usando un selector CSS y con textContent cambias su texto.

addEventListener() ejecuta una función cuando ocurre algo, como un clic. Usa textContent y no innerHTML para mostrar datos que escribe el usuario: así evitas que se cuele código.

Ejemplo práctico
<!-- En el HTML -->
<button id="contar">Pulsa</button>
<p id="veces">0 clics</p>

<script>
  const boton = document.querySelector("#contar");
  const salida = document.querySelector("#veces");
  let clics = 0;

  boton.addEventListener("click", () => {
    clics++;
    salida.textContent = clics + " clics";
  });
</script>

Ejercicio

Completa para reaccionar al clic del botón.

boton.("click", avisar);
Ver la solución

Respuesta: addEventListener. addEventListener(tipo, función) ejecuta la función cada vez que ocurre ese evento.

Lección 9 · Avanzado

Código asíncrono: fetch y async/await

Pedir datos a un servidor tarda, y JavaScript no se queda bloqueado esperando: trabaja con promesas, valores que llegarán más adelante. fetch() hace una petición y devuelve una promesa.

Dentro de una función async puedes escribir await para esperar a la promesa como si fuera código normal. Envuélvelo en try...catch para tratar los fallos de red.

Ejemplo práctico
async function cargarUsuario(id) {
  try {
    const respuesta = await fetch(`https://api.ejemplo.com/usuarios/${id}`);
    if (!respuesta.ok) throw new Error("Error " + respuesta.status);
    const usuario = await respuesta.json();
    console.log(usuario.nombre);
  } catch (error) {
    console.error("No se pudo cargar:", error.message);
  }
}

cargarUsuario(1);

Ejercicio

¿Qué palabra permite usar await dentro de una función?

Ver la solución

Respuesta: async. await solo puede usarse dentro de funciones marcadas con async (o en el nivel superior de un módulo).

Lección 10 · Avanzado

Módulos y paquetes

Cuando un programa crece, se reparte en varios archivos llamados módulos. Con export decides qué ofrece cada archivo y con import lo usas en otro.

npm, el gestor de paquetes que viene con Node.js, descarga bibliotecas de otras personas y apunta en package.json cuáles usa tu proyecto, para que cualquiera pueda instalarlas con npm install.

Ejemplo práctico
// archivo matematicas.js
export function sumar(a, b) {
  return a + b;
}

// archivo principal.js
import { sumar } from "./matematicas.js";
console.log(sumar(2, 3)); // 5

// En la terminal, para añadir una biblioteca al proyecto:
// npm install nombre-del-paquete

Ejercicio

Completa la importación.

import { sumar }  "./matematicas.js";
Ver la solución

Respuesta: from. La sintaxis es import { nombre } from "ruta".

Lección 11 · Avanzado

Clases: moldes para crear objetos

Una clase es un molde para crear objetos que tienen los mismos datos y las mismas acciones. El método constructor se ejecuta al crear cada objeto con new y guarda sus datos en this; los demás métodos son las acciones que puede hacer.

Con extends una clase hereda de otra: aprovecha sus métodos y puede añadir otros nuevos. En el constructor de la clase hija hay que llamar primero a super(), que ejecuta el constructor de la clase madre.

Ejemplo práctico
class Cuenta {
  constructor(titular, saldo = 0) {
    this.titular = titular;
    this.saldo = saldo;
  }

  ingresar(cantidad) {
    this.saldo += cantidad;
    return this.saldo;
  }
}

class CuentaAhorro extends Cuenta {
  constructor(titular, saldo, interes) {
    super(titular, saldo);
    this.interes = interes;
  }

  aplicarInteres() {
    return this.ingresar(this.saldo * this.interes);
  }
}

const cuenta = new CuentaAhorro("Ana", 1000, 0.02);
console.log(cuenta.ingresar(500));    // 1500
console.log(cuenta.aplicarInteres()); // 1530

Escribe el código

Escribe la clase Contador: cada contador nuevo empieza con la propiedad valor a 0, el método sumar() le suma 1 y reiniciar() la vuelve a 0.

Tab escribe una sangría; para salir del editor con el teclado, pulsa Esc y luego Tab. Ctrl + Intro corrige.

Ver la solución
class Contador {
  constructor() {
    this.valor = 0;
  }

  sumar() {
    this.valor += 1;
  }

  reiniciar() {
    this.valor = 0;
  }
}

El constructor pone this.valor = 0 y cada método cambia esa misma propiedad del objeto (this.valor).

Lección 12 · Avanzado

Errores: try, catch y throw

Cuando algo falla (un dato con un formato inesperado, una conexión que se corta…), JavaScript lanza un error y detiene el programa. Con try { … } catch (error) { … } lo capturas y decides qué hacer: avisar a la persona, usar un valor por defecto o volver a intentarlo.

Tú también puedes lanzar errores con throw new Error("mensaje") cuando una función recibe datos sin sentido, para que el fallo se note en vez de seguir con datos erróneos. El bloque finally se ejecuta siempre, haya error o no.

Ejemplo práctico
function leerEdad(texto) {
  const edad = Number(texto);
  if (!Number.isInteger(edad) || edad < 0) {
    throw new Error(`«${texto}» no es una edad válida`);
  }
  return edad;
}

try {
  console.log(leerEdad("30"));   // 30
  console.log(leerEdad("abc"));  // aquí se lanza el error
} catch (error) {
  console.log("No se pudo leer:", error.message);
} finally {
  console.log("Comprobación terminada");
}

Encuentra los errores

leerJson(texto) debería devolver los datos de un texto JSON, o null si el texto no es JSON válido, y el programa debería mostrar «Ana». Tiene 2 errores.

Ver la solución
  • Línea 5: throw vuelve a lanzar un error y el programa se detiene igual. Para devolver null hay que usar return. Corrección: return null;
  • Línea 10: Los nombres de las propiedades distinguen mayúsculas: el JSON tiene nombre, no Nombre, así que se mostraría undefined. Corrección: console.log(datos.nombre);

Lección 13 · Avanzado

Eventos: responder a clics y teclas

Un evento es algo que ocurre en la página: un clic, una tecla pulsada, el envío de un formulario. Con elemento.addEventListener("click", función) indicas qué hacer cada vez que ocurre; la función recibe un objeto event con los detalles, como la tecla pulsada (event.key) o el elemento que lo provocó (event.target).

Al enviar un formulario, el navegador recarga la página. event.preventDefault() lo evita, para que puedas leer y mostrar los datos con JavaScript sin perderlos.

Ejemplo práctico
// HTML: <form id="buscador"><input name="q"><button>Buscar</button></form>
//       <p id="resultado"></p>
const formulario = document.querySelector("#buscador");
const resultado = document.querySelector("#resultado");

formulario.addEventListener("submit", (event) => {
  event.preventDefault(); // no recargar la página
  const texto = formulario.elements.q.value.trim();
  resultado.textContent = texto ? `Buscando «${texto}»…` : "Escribe algo para buscar.";
});

document.addEventListener("keydown", (event) => {
  if (event.key === "Escape") resultado.textContent = "";
});

Ejercicio

¿Qué hace event.preventDefault() dentro del evento submit de un formulario?

Ver la solución

Respuesta: Evita que el navegador envíe el formulario y recargue la página. preventDefault() cancela la acción que el navegador haría por defecto; en un formulario, enviarlo y recargar la página.

Lección 14 · Avanzado

Guardar datos en el navegador con localStorage

localStorage guarda pares clave-valor en el navegador y los conserva aunque cierres la pestaña. Solo almacena texto: para guardar listas u objetos, conviértelos con JSON.stringify() y recupéralos con JSON.parse().

Lo que guardas solo está en ese navegador y ese dispositivo, y cualquier script de la página puede leerlo: no guardes contraseñas ni datos sensibles. En modo privado o con el almacenamiento bloqueado puede fallar, por eso conviene envolverlo en try…catch.

Ejemplo práctico
function guardarTareas(tareas) {
  try {
    localStorage.setItem("tareas", JSON.stringify(tareas));
  } catch {
    console.log("No se han podido guardar las tareas");
  }
}

function cargarTareas() {
  try {
    return JSON.parse(localStorage.getItem("tareas")) ?? [];
  } catch {
    return [];
  }
}

guardarTareas([{ texto: "Comprar pan", hecha: false }]);
console.log(cargarTareas()[0].texto); // "Comprar pan"

Ejercicio

Completa para convertir la lista en texto antes de guardarla.

localStorage.setItem("tareas", JSON.(tareas));
Ver la solución

Respuesta: stringify. JSON.stringify() convierte un objeto o una lista en texto JSON; JSON.parse() hace lo contrario.

Lección 15 · Avanzado

Expresiones regulares: buscar patrones en un texto

Una expresión regular describe un patrón de texto: «cinco dígitos», «algo con forma de correo»… En JavaScript se escriben entre barras, como /\d{5}/ (\d es un dígito y {5}, cinco veces), y el método test() dice si un texto cumple el patrón.

^ y $ marcan el principio y el final del texto; sin ellos, basta con que el patrón aparezca en cualquier parte. Los métodos match() y replace() usan patrones para extraer o sustituir partes de un texto.

Ejemplo práctico
const codigoPostal = /^\d{5}$/;
console.log(codigoPostal.test("28013")); // true
console.log(codigoPostal.test("2801"));  // false

const texto = "Llama al 600 123 456 o al 910 000 000";
console.log(texto.match(/\d{3} \d{3} \d{3}/g)); // ["600 123 456", "910 000 000"]

console.log("hola    mundo".replace(/\s+/g, " ")); // "hola mundo"

Escribe el código

Escribe esHoraValida(texto): devuelve true si el texto es una hora en formato HH:MM entre 00:00 y 23:59 (con dos cifras en cada parte) y false en cualquier otro caso.

Tab escribe una sangría; para salir del editor con el teclado, pulsa Esc y luego Tab. Ctrl + Intro corrige.

Ver la solución
function esHoraValida(texto) {
  return /^([01]\d|2[0-3]):[0-5]\d$/.test(texto);
}

[01]\d|2[0-3] acepta de 00 a 19 o de 20 a 23; [0-5]\d, de 00 a 59. Sin ^ y $, «las 10:00» también se aceptaría.

¿Has terminado? Sigue practicando

Repasa los conceptos en el diccionario, practica con estas herramientas o prueba otro lenguaje: las ideas que has aprendido (variables, condiciones, funciones, objetos…) te servirán en cualquiera.

Proyectos para practicar JavaScript

  • Texto y programación

    Base64, URL y JSON

    Codifica y decodifica Base64 y URL, y valida o formatea JSON con la línea del error.

  • Texto y programación

    Probador de expresiones regulares

    Prueba una expresión regular sobre tu texto, con coincidencias, grupos y explicación en español.

  • Texto y programación

    Comparar dos textos

    Encuentra las diferencias entre dos versiones de un texto, línea a línea y palabra a palabra.

Fuentes consultadas

* Porcentaje de personas que dijeron haber usado JavaScript en la Stack Overflow Developer Survey 2026: Technology (pregunta sobre lenguajes de programación, de scripts y de marcado; todas las respuestas). El progreso de las lecciones se guarda solo en este navegador.