JavaScript es el único lenguaje que entienden todos los navegadores, así que, si alguna vez has usado una página web, ya has ejecutado miles de líneas de JavaScript. Desde que existe Node.js también funciona fuera del navegador: en servidores, herramientas de la terminal y aplicaciones de escritorio. Es fácil de empezar y tiene fama de hacer cosas raras. Este curso explica las dos cosas: cómo se programa bien en JavaScript y por qué esas rarezas no son tan raras.
La ruta: ocho lecciones
Están pensadas para leerse en orden. Las dos primeras están en esta misma página y las demás tienen la suya. Al final hay un test de 24 preguntas para comprobar lo aprendido.
- 1Primeros pasosDónde se ejecuta JavaScript, Node, la consola del navegador, let y const.En esta página
- 2Tipos y valoresLos primitivos, un único tipo numérico, null frente a undefined, == frente a ===.En esta página
- 3Operadores y control de flujoif, switch, los bucles, for…of frente a for…in, ?? y ?.Leer la lección →
- 4Funciones y closuresDeclaraciones y flechas, parámetros, ámbito y las funciones que recuerdan.Leer la lección →
- 5Arrays y objetosmap, filter y reduce, desestructuración, copias que no copian, Map y Set.Leer la lección →
- 6Clases, prototipos y thisCómo funcionan las clases por debajo y a qué apunta this en cada caso.Leer la lección →
- 7Errores y asincroníatry y catch, el bucle de eventos, promesas y async/await.Leer la lección →
- 8Módulos, npm y pruebasimport y export, package.json, node –test y un vistazo a TypeScript.Leer la lección →
Qué necesitas
Un editor de texto (Visual Studio Code es el más usado y es gratis), un navegador y Node.js. No hace falta saber programar en otro lenguaje, pero si ya sabes Python o Java, encontrarás comparaciones que te ahorrarán tiempo.
Lección 1: primeros pasos
Dónde se ejecuta JavaScript
Lo primero que hay que tener claro es la diferencia entre el lenguaje y el entorno. El lenguaje es el mismo en todas partes: variables, funciones, objetos, bucles. Lo que cambia es lo que cada entorno añade. El navegador da acceso a la página (document), a los clics del usuario y al almacenamiento local. Node.js, en cambio, da acceso a los archivos, a la red y a la línea de órdenes, pero no tiene document, porque no hay ninguna página.
Por eso este curso usa Node para casi todo: así los ejemplos se ejecutan en la terminal, sin montar una página, y lo que aprendas te servirá igual en el navegador.
Instalar Node.js
Descárgalo de nodejs.org y elige la versión LTS (soporte a largo plazo), que hoy es la 24. En Linux y macOS también se puede instalar con un gestor de versiones como nvm o fnm, que permite tener varias a la vez. Después, comprueba que funciona:
node -v npm -v
salidav24.22.0 11.19.1
Node trae consigo npm, el gestor de paquetes con el que se instalan bibliotecas de terceros. Lo veremos en la lección 8.
El primer programa
Crea un archivo llamado hola.mjs:
const nombre = "Ana";
const edad = 31;
console.log("Hola, mundo");
console.log(`Hola, ${nombre}. El año que viene tendrás ${edad + 1}.`);node hola.mjs
salidaHola, mundo Hola, Ana. El año que viene tendrás 32.
Tres cosas que conviene fijarse desde ya:
console.logimprime en la terminal (en el navegador, en la consola de las herramientas de desarrollo). Es la herramienta de depuración que más vas a usar.- Las comillas invertidas
`...`crean una plantilla: lo que va dentro de${ }se calcula y se inserta en el texto. Es la forma moderna de construir cadenas. - La extensión
.mjsle dice a Node que el archivo es un módulo moderno, conimportyexport, y en modo estricto, que convierte algunos errores silenciosos en errores visibles. En la lección 8 verás cómo conseguir lo mismo con.jsnormales.
Y en el navegador
Pulsa F12 en cualquier página y abre la pestaña Consola: puedes escribir JavaScript y ver el resultado al momento. Para una página propia, el código va en un archivo aparte que se enlaza con la etiqueta script:
<!doctype html> <html lang="es"> <head> <meta charset="utf-8"> <title>Mi primera página con JavaScript</title> <script type="module" src="app.js"></script> </head> <body> <h1>Cargando…</h1> </body> </html>
// app.js
const titulo = document.querySelector("h1");
titulo.textContent = "Hola desde JavaScript";
console.log("El título ahora dice:", titulo.textContent);consola del navegadorEl título ahora dice: Hola desde JavaScript
Por qué hay que poner type="module" y qué pasa si el script va antes de los elementos que busca está explicado en el ejemplo de la etiqueta script. Un detalle práctico: los módulos no se cargan si abres el archivo con doble clic (file://); hay que servir la carpeta con un servidor local, por ejemplo con npx serve o con el de nuestro ejemplo de servidor web.
let, const y por qué no var
Hay tres formas de declarar una variable. Usa const siempre que puedas y let cuando el valor tenga que cambiar:
const limite = 10; limite = 20;
salidaTypeError: Assignment to constant variable.
Pero ojo, const no congela nada. Impide que la variable apunte a otra cosa, no que cambie lo que hay dentro:
const carrito = ["pan"];
carrito.push("leche");
console.log(carrito);salida[ 'pan', 'leche' ]
¿Y var? Es la forma antigua, y tiene un comportamiento que sorprende a todo el mundo: no respeta los bloques. Una variable declarada con var dentro de un if o de un for sigue existiendo fuera:
if (true) {
var a = "var";
let b = "let";
}
console.log(a);
console.log(b);salidavar
salidaReferenceError: b is not defined
Con let la variable muere al cerrar la llave, que es lo que uno espera. Además, let y const no dejan declarar dos veces el mismo nombre, y un const sin valor inicial no tiene sentido:
let total = 1; let total = 2;SyntaxError: Identifier 'total' has already been declared
const x;SyntaxError: Missing initializer in const declaration
return seguido de un salto de línea. Lo contamos en las rarezas de JavaScript. En este curso los ponemos siempre.Lección 2: tipos y valores
JavaScript es un lenguaje de tipado dinámico: las variables no tienen tipo, los valores sí. La misma variable puede guardar un número y después un texto. Y es de tipado débil: cuando una operación mezcla tipos, el lenguaje intenta convertirlos en vez de dar un error. Las dos cosas explican la mitad de las sorpresas de JavaScript.
Los tipos
Hay siete tipos primitivos (valores simples que no se pueden modificar) y, aparte, los objetos, que incluyen arrays, funciones y fechas. El operador typeof dice de qué tipo es un valor:
console.log(typeof 42, typeof 3.14, typeof "texto", typeof true);
console.log(typeof undefined, typeof 10n, typeof Symbol("id"));
console.log(typeof null, typeof { a: 1 }, typeof [1, 2], typeof function () {});
console.log(Array.isArray([1, 2]));salidanumber number string boolean undefined bigint symbol object object object function true
Dos detalles: typeof null dice "object", que es un error de la primera versión del lenguaje que ya no se puede corregir sin romper millones de páginas; y los arrays también son "object", así que para distinguirlos se usa Array.isArray.
Un solo tipo de número
Casi todos los lenguajes distinguen enteros y decimales. JavaScript no: todo number es un número de coma flotante de 64 bits, el mismo double de C o de Java. Eso tiene consecuencias:
console.log(7 / 2);
console.log(Math.trunc(7 / 2), 7 % 2);
console.log(1 / 0, -1 / 0);
console.log(0 / 0, Number("hola"));
console.log(Number.isNaN(Number("hola")));salida3.5 3 1 Infinity -Infinity NaN NaN true
La división nunca es entera (para eso está Math.trunc), dividir entre cero no da error sino Infinity, y una operación sin sentido da NaN, que significa «no es un número» aunque su tipo sea number. Para saber si algo es NaN se usa Number.isNaN; por qué no sirve === NaN está en las rarezas, junto al famoso 0.1 + 0.2.
La otra consecuencia: los enteros solo son exactos hasta 253 – 1. Por encima, se pierden unidades sin avisar. Para enteros grandes existe BigInt, que se escribe con una n al final:
console.log(Number.MAX_SAFE_INTEGER); console.log(9007199254740993); console.log(9007199254740993n + 1n);
salida9007199254740991 9007199254740992 9007199254740994n
El segundo número sale con un 2 al final en lugar de un 3: no cabe en un double y se redondea al más cercano. Los BigInt no se pueden mezclar con números normales sin convertirlos:
10n + 1TypeError: Cannot mix BigInt and other types, use explicit conversions
Para mostrar números al usuario, toLocaleString pone los separadores del idioma que le pidas: (1234567.891).toLocaleString("es-MX") da 1,234,567.891.
Cadenas
const s = "hola";
console.log(s.length, s[0], s.toUpperCase(), s);
console.log(s.at(-1), s.slice(1, 3), s.includes("ol"));
const precio = 1299.5;
console.log(`Total: $${precio.toFixed(2)} USD`);salida4 h HOLA hola a ol true Total: $1299.50 USD
Fíjate en que s.toUpperCase() no cambia s: devuelve una cadena nueva. Las cadenas son inmutables, y si intentas cambiar una letra, en un módulo obtienes un error:
s[0] = "H"TypeError: Cannot assign to read only property '0' of string 'hola'
En un script antiguo, sin modo estricto, la misma línea no da error: simplemente no hace nada. Lo comprobamos, y es un buen ejemplo de por qué conviene trabajar siempre con módulos.
Conversiones automáticas
Aquí está la parte del tipado débil. Cuando mezclas tipos, JavaScript convierte por su cuenta, y la regla del + es distinta a la del resto de operadores: si uno de los dos lados es texto, + concatena; los demás operadores convierten a número.
console.log(1 + "1");
console.log("3" * "4");
console.log("10" - 1);
console.log(true + 1);
console.log(Number("42"), Number(""), Number("4 2"), parseInt("42px"));salida11 12 9 2 42 0 NaN 42
La lección práctica: convierte tú, de forma explícita, con Number(...) o String(...), sobre todo con lo que llega de un formulario, que siempre es texto. Y cuidado con Number(""), que da 0 y no NaN: una casilla vacía no da error.
null y undefined
JavaScript tiene dos formas de decir «no hay nada». undefined es lo que sale cuando algo no se ha definido: una variable sin valor, una propiedad que no existe, una función sin return. null lo pone el programador a propósito para decir «vacío».
let sinValor;
const persona = { nombre: "Ana", telefono: null };
console.log(sinValor);
console.log(persona.correo);
console.log(persona.telefono);
function f() {}
console.log(f());salidaundefined undefined null undefined
== frente a ===
Hay dos operadores de igualdad. === compara sin convertir: si los tipos son distintos, son distintos. == convierte antes de comparar, con unas reglas que casi nadie recuerda enteras:
console.log(0 == "0", 0 === "0"); console.log(0 == "", "0" == ""); console.log(null == undefined, null === undefined); console.log(NaN == NaN, Number.isNaN(NaN)); console.log([1, 2] === [1, 2]);
salidatrue false true false true false false true false
La segunda línea es la que retrata el problema: 0 es igual a "" y a "0", pero "0" y "" no son iguales entre sí. Con == la igualdad deja de ser transitiva. La regla es sencilla: usa siempre === y !==. La única excepción que algunos aceptan es x == null, que es cierto para null y undefined a la vez.
La última línea también sorprende: dos arrays con el mismo contenido no son iguales, porque === compara objetos por identidad (si son el mismo objeto), no por contenido. Lo veremos a fondo en la lección 5.
| Comparación | Con == | Con === |
|---|---|---|
0 y "0" | true | false |
0 y "" | true | false |
null y undefined | true | false |
NaN y NaN | false | false |
[1, 2] y [1, 2] | false | false |
Verdadero y falso
En un if, cualquier valor se convierte en verdadero o falso. Solo hay ocho valores que cuentan como falsos; todos los demás son verdaderos:
const falsos = [false, 0, -0, 0n, "", null, undefined, NaN];
console.log(falsos.map(Boolean).join(" "));
const verdaderos = ["0", "false", " ", [], {}, -1, Infinity];
console.log(verdaderos.map(Boolean).join(" "));
const cantidad = 0;
console.log(cantidad || 10, cantidad ?? 10);salidafalse false false false false false false false true true true true true true true 10 0
La última línea adelanta algo de la lección 3: || sustituye cualquier valor falso, incluido un 0 legítimo, mientras que ?? solo sustituye null y undefined. Si la cantidad puede ser cero, la buena es ??.
Cómo está hecho este curso
Todo el código se ejecutó con Node.js 24.22 en un contenedor limpio antes de publicarlo, y las salidas están copiadas de esa ejecución; lo que corresponde al navegador se probó en Chromium. Cuando algo dice «esto da error», es porque se ejecutó y se copió el mensaje literal.
¿Buscas una receta concreta en vez de una lección? En Ejemplos de JavaScript hay archivos, JSON, fetch, un servidor web, el DOM y eventos. Y si quieres comparar con otros lenguajes, están los cursos de Python, Java, Go y Rust.
