Curso de JavaScript desde cero, en español

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.

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.

El lenguaje JavaScript es el mismo en el navegador y en Node.js; cambia lo que cada entorno añade: el DOM y fetch en el navegador, archivos y servidores en NodeUn mismo lenguaje, dos sitios donde se ejecutaEl lenguaje: variables, funciones, objetos, promesas…lo que enseña este curso, igual en los dos ladosEn el navegadorChrome, Firefox, Safari…document y el DOMeventos: click, input…fetch y localStoragecanvas, audio, vídeoEn Node.jsen tu equipo o en un servidorarchivos: node:fsservidores: node:httpprocess.argv y variablespaquetes de npm

El lenguaje es el mismo; cada entorno añade sus propias herramientas. Esquema: decodigo.com.

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.log imprime 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 .mjs le dice a Node que el archivo es un módulo moderno, con import y export, 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 .js normales.

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' ]

const impide reasignar la variable, pero el array al que apunta se puede modificarconst fija la variable, no el contenidoconst carritoel array, en memoria[«pan», «leche»]apunta acarrito = [] da TypeErrorcambiar a qué apunta: prohibidocarrito.push(«leche») funcionacambiar lo de dentro: permitido

La variable es una flecha hacia el valor. const fija la flecha, pero el array sigue siendo modificable. Esquema: decodigo.com.

¿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
¿Y el punto y coma? JavaScript lo inserta solo al final de la mayoría de las líneas, así que un programa sin ellos suele funcionar. Pero «la mayoría» no es «todas», y hay un caso famoso que lo demuestra: un 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

Los siete tipos primitivos de JavaScript y los objetos, con lo que devuelve typeof en cada caso; typeof null devuelve objectLos tipos de JavaScript y lo que responde typeofSiete primitivos: valores simples que no se modificannumber42, 3.14, NaN«number»string«hola»«string»booleantrue, false«boolean»undefinedundefined«undefined»nullnull«object»bigint10n«bigint»symbolSymbol(«id»)«symbol»Y todo lo demás es un objeto: se guarda por referencia y sí se puede modificar{ a: 1 }«object»[1, 2]«object»function () {}«function»new Date()«object»La fila de abajo es lo que devuelve typeof. El de null es un error histórico que ya no se puede corregir.

Siete primitivos y los objetos. Debajo de cada uno, lo que devuelve typeof. Esquema: decodigo.com.

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ónCon ==Con ===
0 y "0"truefalse
0 y ""truefalse
null y undefinedtruefalse
NaN y NaNfalsefalse
[1, 2] y [1, 2]falsefalse

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:

Los ocho valores falsos de JavaScript: false, 0, -0, 0n, cadena vacía, null, undefined y NaN; el resto, incluidos la cadena 0, el array vacío y el objeto vacío, son verdaderosLos únicos ocho valores que cuentan como falsosfalse0-00n«»nullundefinedNaNTodo lo demás es verdadero, incluidos estos, que engañan:«0»«false»» «[]{}-1

Los ocho valores falsos. La cadena «0», el array vacío y el objeto vacío son verdaderos. Esquema: decodigo.com.
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.