Ya sabes qué es HTML y qué es CSS: la estructura y el aspecto de una página. Ahora llega la tercera capa: JavaScript, que añade el comportamiento. Qué pasa cuando el usuario hace clic, qué datos se muestran, cómo se actualizan sin recargar la página. Todo eso es JS.
Este capítulo no empieza por eventos ni por el DOM. Empieza por lo más básico: guardar un valor con un nombre. Sin eso, no hay programa posible.
Seguimos con el Overwatch Team Builder. Vamos a declarar las variables de un héroe y a mostrarlo por consola. La consola de aquí abajo es la misma que la pestaña Consola de las DevTools del navegador (F12): ya la conoces.
Qué es una variable#
Una variable es una caja con nombre que guarda un valor. Le pones una etiqueta, metes algo dentro y luego la usas por ese nombre.
// declara una variable llamada nombre con el valor 'Tracer'
const nombre = 'Tracer';
// Tracer — ahora puedes usar ese nombre en cualquier parte del código
console.log(nombre);Tres partes:
const— la palabra clave que le dice a JavaScript cómo declarar la variable (luego vemosletyvar).nombre— el identificador que eliges tú. Puede ser casi cualquier palabra, sin espacios.'Tracer'— el valor que guardas.
A partir de aquí, cada vez que escribas nombre en tu código, JavaScript sabe
que se refiere a 'Tracer'.
const: por defecto#
const es la forma de declarar una variable cuyo valor no va a cambiar.
Una vez asignado, no puedes reasignarlo:
// declara partidas y le asigna 120; a partir de aquí no puede cambiar
const partidas = 120;
// TypeError: no se puede reasignar una constante
partidas = 150;Esto es una ventaja, no un límite. Si declaras algo como const y más adelante
alguien intenta cambiarlo por accidente, JavaScript lanza un error en ese preciso
momento. El bug no se esconde: aparece enseguida.
La regla de trabajo: empieza siempre con const. Cambia a let solo cuando
de verdad necesites reasignar el valor.
let: cuando el valor cambia#
let permite reasignar la variable después de declararla:
// declara estado con el valor inicial 'disponible'
let estado = 'disponible';
// reasigna: ahora estado vale 'lesionada'
estado = 'lesionada';
// lesionada
console.log(estado);Cuándo usarla: cuando el valor evoluciona con el tiempo. Un contador que sube,
un estado que cambia entre partidas, una posición que se actualiza. Si el valor
es fijo, es const.
var: legacy#
var existe desde los orígenes de JavaScript. Aún funciona, pero tiene dos
comportamientos que sorprenden cuando el código crece:
- No respeta los bloques. Un bloque es cualquier trozo de código encerrado
entre llaves
{ }.letyconstquedan confinados dentro del bloque donde los declaras;var, en cambio, los ignora y se extiende al ámbito que lo rodea. Esto produce variables que “se escapan” y aparecen donde no las esperas:
// Un bloque se delimita con llaves { }.
{
// var declarada dentro del bloque
var escapada = 'var vive fuera del bloque';
// let declarada dentro del bloque
let confinada = 'let vive solo dentro del bloque';
}
// Aquí estamos FUERA del bloque { } de arriba.
// var escapada — se lee sin problema: se escapó del bloque
console.log('var desde fuera: ' + escapada);
// let confinada no existe aquí: daría ReferenceError si intentaras leerla
// console.log(confinada); // ReferenceError: confinada is not defined- Sufre hoisting: JavaScript mueve la declaración al principio del bloque
más amplio que la contiene, de forma que puedes usar la variable antes de
declararla. El valor es
undefinedhasta que llegas a la línea de asignación, lo que puede confundir:
// Hoisting con var: la declaración sube, pero no el valor
// undefined — no da error, pero el valor no está
console.log('antes de declarar: ' + posicion);
// la asignación ocurre aquí
var posicion = 'primer puesto';
// primer puesto
console.log('despues de declarar: ' + posicion);El código moderno no usa var. Lo verás en código antiguo o en tutoriales
desactualizados. Aquí lo mencionamos para que lo reconozcas, no para que lo uses.
Los conceptos de alcance (scope) y hoisting se ven a fondo en un capítulo posterior. Por ahora, la regla práctica basta:
constpor defecto,letcuando necesitas reasignar,varnunca.
Los tipos primitivos#
Cada valor que guardas en una variable tiene un tipo: qué clase de dato es. JavaScript tiene cinco tipos primitivos que necesitas conocer ahora:
string — texto entre comillas simples o dobles:
// string con comillas simples
const rol = 'Apoyo';
// string con comillas dobles; ambas formas son válidas
const saludo = "Hola desde el equipo";
// Apoyo
console.log(rol);
// Hola desde el equipo
console.log(saludo);number — cualquier número, entero o decimal. JavaScript no distingue entre
los dos: todos son number:
// número entero
const partidas = 120;
// número decimal — sigue siendo type number, no "float" ni "decimal"
const winrate = 0.65;
// 120
console.log(partidas);
// 0.65
console.log(winrate);boolean — solo dos valores posibles: true o false. Sin comillas; si les
pones comillas, son strings:
// boolean: el héroe está activo en el equipo
const activo = true;
// boolean: el héroe no ha sido eliminado esta ronda
const eliminado = false;
// true
console.log(activo);
// false
console.log(eliminado);null — ausencia deliberada. Lo usas cuando quieres dejar claro que “aquí no hay dato” por decisión propia:
// null: el héroe no tiene sponsor todavía (decisión consciente)
const sponsor = null;
// null
console.log(sponsor);undefined — la variable existe, pero no se le ha dado ningún valor todavía. JavaScript lo asigna automáticamente cuando declaras sin valor:
// no se asignó ningún valor; JS la inicializa a undefined
let sustituta;
// undefined
console.log(sustituta);La diferencia entre null y undefined es de intención. undefined aparece
solo; null lo pones tú. Si ves undefined donde esperabas un valor, suele ser
un bug. Si ves null, alguien lo puso ahí a propósito.
Existen también
bigint(números enteros muy grandes, fuera del alcance de este capítulo) ysymbol(identificadores únicos, para uso avanzado). No los necesitarás hasta mucho más adelante.
typeof: ver el tipo de un valor#
typeof es un operador que devuelve el tipo de un valor como string:
// 'string' — texto entre comillas
console.log(typeof 'Tracer');
// 'number' — entero o decimal, siempre 'number'
console.log(typeof 120);
// 'boolean' — true o false
console.log(typeof true);
// 'undefined' — sin valor asignado
console.log(typeof undefined);
// 'object' — error histórico de JS; null es primitivo, no objeto
console.log(typeof null);Úsalo para inspeccionar valores cuando no estás seguro del tipo que tienes.
La forma más directa de usarlo es envolviéndolo en console.log, como en el
playground de abajo: lo ves impreso y puedes confirmar que el tipo es el que
esperabas antes de seguir trabajando.
console.log con concatenación#
Ya conoces console.log de las DevTools. En JavaScript lo usas para mostrar
valores y seguir la pista de tu código:
// Heroe: Tracer
console.log('Heroe: ' + nombre);
// Partidas: 120
console.log('Partidas: ' + partidas);Regla importante en este entorno: no separes argumentos con comas.
console.log('Rol:', rol) genera dos entradas separadas en la consola de
aquí abajo. Para que salga una sola línea, concatena con +:
// una sola línea: "Rol: Apoyo"
console.log('Rol: ' + rol);Más adelante aprenderás los template literals (${}), que hacen esto más cómodo.
Por ahora, concatenación: es lo que corresponde a este punto del curso.
Pruébalo#
Aquí tienes las variables de Tracer declaradas, con concatenación y typeof.
Cambia el valor de nombre o de partidas y mira cómo se actualiza la consola.
Prueba también a cambiar const por let en alguna variable y luego reasignarla.
Comprueba lo que sabes#
Pregunta 1 de 5
¿Cuál es la diferencia principal entre const y let?
Tu turno#
Lo que se entiende leyendo no es lo mismo que lo que sabes escribir. Declara las variables de Mercy y muestra el resumen en consola. Cuando lo tengas (o si te atascas), despliega las soluciones y fíjate en el salto de un nivel al siguiente.
Ejercicio · en esta página
Declara tu primer héroe
Declara las variables del héroe Mercy y muestra en consola cada campo por separado y luego una línea de resumen concatenada. Datos: nombre Mercy, rol Apoyo, partidas 200, victorias 130, activo true.
Paso 1: Que funcione
- Los cinco campos aparecen en consola con los valores correctos.
- La línea de resumen concatenada es correcta.
- Vale con var y nombres cortos.
Paso 2: Que esté pulido
- Usa const y let en lugar de var.
- Los nombres de variable son descriptivos: nombre, rol, partidas, victorias, activo.
- Cada variable tiene el tipo correcto (string, number o boolean según el dato).
Paso 3: Que sea excelente
- const para todo lo que no se reasigna; let solo donde haya reasignación real.
- Un comentario explica por qué const por defecto evita bugs.
- Los datos del héroe están agrupados visualmente con un comentario de sección.
- Usa typeof para verificar en consola que cada variable tiene el tipo esperado.
Ver soluciones
// ════════════════════════════════════════════════════════════════════════════
// NIVEL OK — "funciona"
//
// Enfoque base: variables declaradas con var, nombres cortos y poco
// descriptivos. Funciona: los valores son correctos y aparecen en consola.
//
// Sus límites (los que arregla el nivel "Mejor"):
// - var tiene un alcance de función, no de bloque. En el código de arriba
// puede colarse sin avisar donde no la esperas (hoisting). No es el problema
// aquí, pero es el hábito que queremos evitar desde el principio.
// - Los nombres (a, b, c…) no se leen solos: obligan a recordar qué guarda
// cada variable.
// - Usa let para todo, incluso cuando nada se reasigna jamás. El compilador
// no puede ayudarte a detectar un cambio accidental.
// Aun así: los valores son los correctos y la consola muestra todo. Eso vale
// como OK.
// ════════════════════════════════════════════════════════════════════════════
// nombre del héroe (string)
var a = "Mercy";
// rol en el equipo (string)
var b = "Apoyo";
// total de partidas jugadas (number)
var c = 200;
// total de victorias (number)
var d = 130;
// el héroe está activo en el equipo (boolean)
var e = true;
// muestra el nombre del héroe
console.log("Heroe: " + a);
// muestra el rol
console.log("Rol: " + b);
// muestra el total de partidas
console.log("Partidas: " + c);
// muestra el total de victorias
console.log("Victorias: " + d);
// muestra si el héroe está activo
console.log("Activo: " + e);
// línea de resumen concatenada
console.log(
"Resumen: " + a + " (" + b + ") — " + c + " partidas, " + d + " victorias",
); Por qué este nivel
- Funciona: los valores son correctos y aparecen en consola. Ese es el primer requisito de cualquier solución.
- Usa var, que tiene un alcance de función y un comportamiento de hoisting que sorprende cuando el código crece. No es el problema aquí, pero es el hábito que queremos evitar desde el principio.
- Los nombres (a, b, c) no se leen solos: obligan a recordar qué guarda cada variable. En un fichero real, con decenas de variables, eso cuesta tiempo y errores.
// ════════════════════════════════════════════════════════════════════════════
// NIVEL MEJOR — "pulido"
//
// Por qué mejora a OK:
// - Cambia var por const/let: const para todo lo que no se reasigna, let
// solo si de verdad hay reasignación posterior (aquí no la hay, así que
// todo es const). Esto evita cambios accidentales.
// - Nombres descriptivos: nombre, rol, partidas, victorias, activo se leen
// solos. Dentro de seis meses sabrás qué guarda cada variable sin mirar
// el contexto.
// - Los tipos son los correctos: string donde toca, number donde toca,
// boolean donde toca. En OK todo era string porque var no obliga a pensar
// en el tipo; aquí es deliberado.
//
// Lo que todavía deja para "Excelente":
// - Las variables están sueltas, sin indicar que pertenecen al mismo héroe.
// - No hay ningún comentario que explique la decisión de const por defecto.
// ════════════════════════════════════════════════════════════════════════════
// nombre del héroe (string); const: este valor no cambiará
const nombre = "Mercy";
// rol en el equipo (string)
const rol = "Apoyo";
// total de partidas jugadas (number)
const partidas = 200;
// total de victorias (number)
const victorias = 130;
// el héroe está activo en el equipo (boolean)
const activo = true;
// muestra el nombre del héroe
console.log("Heroe: " + nombre);
// muestra el rol
console.log("Rol: " + rol);
// muestra el total de partidas
console.log("Partidas: " + partidas);
// muestra el total de victorias
console.log("Victorias: " + victorias);
// muestra si el héroe está activo
console.log("Activo: " + activo);
// línea de resumen concatenada
console.log(
"Resumen: " +
nombre +
" (" +
rol +
") — " +
partidas +
" partidas, " +
victorias +
" victorias",
); Por qué es mejor que el anterior
- Reemplaza var por const: ahora si alguien intenta reasignar nombre o partidas por error, JS lanza un TypeError en esa misma línea, antes de que el bug se propague.
- Nombres descriptivos: nombre, rol, partidas, victorias, activo se leen solos sin contexto adicional.
- Tipos deliberados: string donde toca, number donde toca, boolean donde toca. En OK todo era implícito; aquí es una decisión consciente.
// ════════════════════════════════════════════════════════════════════════════
// NIVEL EXCELENTE — "óptimo"
//
// Por qué mejora a Mejor:
// - const por defecto y let SOLO donde hay reasignación real. En este
// ejercicio no hay reasignación, así que todo es const. El comentario
// debajo explica el porqué: usar const hace que el motor de JS (y tú mismo)
// detecte al instante si alguien intenta cambiar un valor que debería ser
// fijo. Es el primer escudo contra bugs accidentales.
// - Las variables relacionadas se agrupan visualmente con un comentario de
// sección. Cuando este fichero crezca (más héroes, más campos), cada bloque
// se lee como una unidad coherente.
// - El typeof de cierre no es decorativo: demuestra que has elegido los tipos
// de forma deliberada (string, number, boolean). Cualquier lector del código
// puede ver en un vistazo que los tipos son los correctos.
// ════════════════════════════════════════════════════════════════════════════
// ─── Datos del héroe ───────────────────────────────────────────────────────
// const por defecto: si algo intenta reasignar estas variables, JS lo
// detecta y lanza un error inmediatamente, antes de que el bug se propague.
// Usa let solo cuando el valor deba cambiar con el tiempo (un contador, un
// estado que se actualiza). Aquí nada cambia, así que todo es const.
const nombre = "Mercy";
const rol = "Apoyo";
const partidas = 200;
const victorias = 130;
const activo = true;
// ─── Consola ───────────────────────────────────────────────────────────────
console.log("Heroe: " + nombre);
console.log("Rol: " + rol);
console.log("Partidas: " + partidas);
console.log("Victorias: " + victorias);
console.log("Activo: " + activo);
console.log(
"Resumen: " +
nombre +
" (" +
rol +
") — " +
partidas +
" partidas, " +
victorias +
" victorias",
);
// ─── Verificación de tipos ─────────────────────────────────────────────────
// typeof devuelve el tipo de un valor como string.
// Sirve para confirmar que cada variable tiene el tipo que esperas.
// 'string'
console.log("Tipo de nombre: " + typeof nombre);
// 'number'
console.log("Tipo de partidas: " + typeof partidas);
// 'boolean'
console.log("Tipo de activo: " + typeof activo); Por qué es mejor que el anterior
- const para todo y let solo si hay reasignación real. En este ejercicio nada se reasigna, así que todo es const. El comentario en el código explica el porqué: es el primer escudo contra bugs accidentales.
- Los datos del héroe están agrupados en su propia sección con un comentario de bloque. Cuando este fichero crezca (más héroes, más campos), cada grupo se lee como una unidad coherente.
- El bloque de typeof al final no es decorativo: confirma en consola que los tipos son los esperados. Es una forma de documentar la intención y de detectar al instante si alguien pone "200" (string) en lugar de 200 (number).