learning-front

Nivel 2 · JavaScript: fundamentos del lenguaje

Template literals: construir strings

Interpolar valores y escribir varias líneas sin pelearte con la concatenación. La base para montar texto y HTML desde JS.

Hasta ahora, para meter el valor de una variable dentro de un string usábamos +. Funciona, pero tiene un coste: paréntesis para agrupar expresiones, espacios que se olvidan, líneas que crecen horizontalmente hasta que dejan de caber en pantalla. Los template literals resuelven ese problema y desbloquean algo más: los strings multilínea sin trucos.

A partir de este capítulo usaremos ${} en todo el curso. Es la sintaxis estándar en cualquier codebase moderno.

El problema con la concatenación#

Mira este string construido con +:

javascript
// variable con el nombre del héroe
const nombre = 'Tracer';
// variable con el rol
const rol = 'Daño';
// número de partidas jugadas
const partidas = 120;
// número de victorias
const victorias = 78;

const resumen = 'Héroe: ' + nombre + ' (' + rol + ')' + '\n'
  + 'Partidas: ' + partidas + ' | Winrate: ' + (victorias / partidas * 100).toFixed(1) + '%';
// cada fragmento se une con +; los espacios se añaden dentro de las comillas
// '\n' es un carácter especial que representa un salto de línea

Funciona. Pero para leerlo hay que ir saltando entre + y comillas, y para escribirlo es fácil olvidar un espacio o un +. Si encima necesitas varias líneas, añades \n manualmente.

Template literals: backticks y ${}#

Un template literal se escribe con acento grave (`) en lugar de comillas. Dentro, puedes meter cualquier expresión de JavaScript con ${}:

javascript
// variable con el nombre del héroe
const nombre = 'Tracer';
// variable con el rol
const rol = 'Daño';

// backticks abren el template literal; ${nombre} y ${rol} se sustituyen por su valor
const saludo = `Héroe: ${nombre} (${rol})`;
// Héroe: Tracer (Daño)
console.log(saludo);

El ${...} evalúa lo que haya dentro y lo convierte en texto. Puede ser una variable, una operación aritmética, una llamada a función… cualquier expresión:

javascript
// número de partidas jugadas
const partidas = 120;
// número de victorias
const victorias = 78;

// la expresión (victorias / partidas * 100).toFixed(1) se calcula y su resultado
// se inserta en el string; toFixed(1) formatea el número a exactamente un decimal
// Winrate: 65.0%
console.log(`Winrate: ${(victorias / partidas * 100).toFixed(1)}%`);

Ese .toFixed(1) es un método: una herramienta que el propio número trae incorporada y que llamas poniendo un punto, su nombre y paréntesis. Los métodos los verás a fondo más adelante; por ahora solo lo usamos aquí para redondear a exactamente un decimal.

Multilínea sin trucos#

Dentro de un template literal, un salto de línea en el código fuente es un salto de línea en el string. No hace falta \n:

javascript
// el salto de línea en el código fuente se convierte en salto de línea en el string
// no hace falta escribir '\n' en ningún sitio
const ficha = `Héroe: ${nombre}
Rol: ${rol}
Partidas: ${partidas}`;

// imprime el string con los saltos de línea reales
console.log(ficha);
// Héroe: Tracer
// Rol: Daño
// Partidas: 120

Compara con el equivalente en concatenación:

javascript
// mismo resultado que el template literal de arriba, pero usando '+' y '\n'
// '\n' fuerza el salto de línea
const fichaVieja = 'Héroe: ' + nombre + '\n'
  + 'Rol: ' + rol + '\n'
  + 'Partidas: ' + partidas;

El resultado es idéntico. El template literal es simplemente más legible.

Extraer las expresiones complejas#

Cuando la expresión dentro del ${} es larga, lo mejor es calcularla antes y darle un nombre:

javascript
// Feo: la expresión dentro del ${} obliga a leerla completa para saber qué es.
const fichaDirecta = `Winrate: ${(victorias / partidas * 100).toFixed(1)}%`;

// Mejor: calculamos antes y guardamos en una variable con nombre descriptivo.
// número con un decimal
const winratePct = (victorias / partidas * 100).toFixed(1);
// ${winratePct} se lee de un vistazo
const fichaLimpia = `Winrate: ${winratePct}%`;

Regla práctica: si tienes que pararte a leer lo que hay dentro de un ${}, extráelo a una variable.

Métodos de string y número que usarás en todo el curso#

Los strings y los números en JavaScript traen herramientas incorporadas que se llaman con un punto seguido de su nombre y unos paréntesis: valor.metodo(). Son los métodos. Por qué un valor puede llevar funciones “pegadas” lo entenderás del todo en el capítulo de objetos; por ahora te basta con el patrón valor.metodo() y saber qué hace cada uno. Presentamos los tres que el curso usa a partir de aquí —en cada ficha, Firma es solo la forma de llamar al método: qué recibe entre paréntesis y qué te devuelve—.

.toFixed(n) — formatear un número a n decimales#

Firma: numero.toFixed(n) → devuelve un string con exactamente n decimales.

javascript
// winrate como número entre 0 y 1
const winrate = 0.65;

// multiplicamos por 100 para obtener el porcentaje
// toFixed(1) lo redondea a un decimal y lo convierte en string
const porcentaje = (winrate * 100).toFixed(1);
// "65.0"
console.log(porcentaje);

// también funciona con más decimales
// toFixed(2) da exactamente dos cifras decimales
const precio = (1.5).toFixed(2);
// "1.50"
console.log(precio);

Ya lo usaste en la sección anterior para formatear el winrate. Lo verás en la mayoría de los capítulos siguientes.

.toLowerCase() — convertir a minúsculas#

Firma: string.toLowerCase() → devuelve el mismo string con todas las letras en minúsculas.

javascript
// nombre tal como lo introduce el usuario (podría llevar mayúsculas)
const entrada = 'TRACER';

// toLowerCase no modifica la variable original: devuelve un string nuevo
const enMinusculas = entrada.toLowerCase();
// "tracer"
console.log(enMinusculas);

Esto es útil al comparar texto introducido por el usuario: si el usuario escribe “TRACER” y tú comparas contra 'tracer', la comparación falla. Con .toLowerCase() en ambos lados el resultado es predecible.

.includes(texto) — comprobar si un string contiene otro#

Firma: string.includes(texto) → devuelve true si texto aparece en cualquier parte de string, false si no.

javascript
// descripción del héroe
const descripcion = 'Tracer, rol Daño, especialista en movilidad';

// ¿contiene la palabra "Daño"?
// true: "Daño" sí aparece en la descripción
const esDano = descripcion.includes('Daño');
// true
console.log(esDano);

// ¿contiene "Tanque"?
// false: "Tanque" no aparece
const esTanque = descripcion.includes('Tanque');
// false
console.log(esTanque);

Lo usarás cuando tengas que buscar o filtrar texto: por ejemplo, un buscador de héroes que filtra por nombre conforme el usuario escribe.


Pruébalo tú#

El playground compara la concatenación con el template literal. Fíjate en que ambos producen la misma salida, pero el segundo es más fácil de escribir y de leer. Prueba a cambiar el nombre o las partidas y observa cómo se actualiza la ficha.

Comprueba lo que sabes#

Pregunta 1 de 5

¿Con qué carácter se abre y cierra un template literal?

Tu turno#

Construye la ficha de un héroe desde cero. El starter tiene los datos listos; tu tarea es rellenar los TODO con template literals. Cuando lo tengas, despliega las soluciones y fíjate en el salto de un nivel al siguiente.

Ejercicio · en esta página

Construye la ficha de un héroe

Tienes los datos de un héroe del Overwatch Team Builder. Construye una ficha de resumen con template literals: nombre, rol, partidas, victorias y el winrate formateado con un decimal.

Paso 1: Que funcione

  • La ficha se imprime en la consola con todos los datos.
  • Usas backticks al menos en parte del string.
  • El winrate aparece en la salida (aunque sea sin formatear o calculado dentro del ${}).
Ver soluciones
// ════════════════════════════════════════════════════════════════════════════
// NIVEL OK — "funciona"
//
// Usa template literals para los strings principales, pero mezcla
// concatenación en algunos sitios y mete el cálculo del winrate directamente
// dentro del ${}, lo que lo hace difícil de leer de un vistazo.
//
// Sus límites (los que arregla el nivel "Mejor"):
//   - La expresión `(victorias / partidas * 100).toFixed(1)` dentro del ${}
//     obliga a pararte a leer: no se ve a simple vista qué es.
//   - El encabezado de la ficha aún usa concatenación, sin motivo.
//   - Sin multilínea real: los saltos se simulan con \n en vez de aprovechar
//     que los template literals los admiten de forma nativa.
// Aun así: la ficha se imprime correcta. Eso vale como OK.
// ════════════════════════════════════════════════════════════════════════════

// nombre del héroe
const nombre = "Mercy";
// rol en el equipo
const rol = "Apoyo";
// total de partidas jugadas
const partidas = 200;
// total de victorias
const victorias = 130;

// El cálculo va directo dentro del ${}: funciona, pero cuesta leerlo.
// mezcla de concatenación ('+' y '\n') e interpolación (backticks y ${})
// la expresión de cálculo va dentro del ${}: funciona, pero obliga a leerla completa
const ficha =
  // cabecera con salto de línea manual
  "== Héroe ==" +
  "\n" +
  // template literal por línea
  `Nombre: ${nombre}` +
  "\n" +
  `Rol: ${rol}` +
  "\n" +
  `Partidas: ${partidas}` +
  "\n" +
  `Victorias: ${victorias}` +
  "\n" +
  // cálculo inline dentro del ${}
  `Winrate: ${((victorias / partidas) * 100).toFixed(1)}%`;

// imprime la ficha completa en la consola
console.log(ficha);

Por qué este nivel

  • Produce la ficha correcta y ya usa template literals en algunos strings.
  • Pero mezcla concatenación con interpolación sin motivo: elige uno.
  • La expresión dentro del ${} obliga a pararse a leer; el salto de línea sigue siendo \n manual.