diff --git a/modules/20-arithmetics/60-infinity/es/README.md b/modules/20-arithmetics/60-infinity/es/README.md
index a2bdac62..ca5f7689 100644
--- a/modules/20-arithmetics/60-infinity/es/README.md
+++ b/modules/20-arithmetics/60-infinity/es/README.md
@@ -13,4 +13,4 @@ Infinity - 4; // Infinity
Infinity * Infinity; // Infinity
```
-Sin embargo, hay algunos ejemplos en los que el infinito es útil. Este tema se analiza en detalle en Hexlet.
+Sin embargo, hay algunos casos en los que el infinito resulta necesario. Por ejemplo, para fijar un límite superior e inferior o, al contrario, para quitarlo.
diff --git a/modules/31-advanced-strings/25-interpolation/es/README.md b/modules/31-advanced-strings/25-interpolation/es/README.md
index 9f070b13..fff83d1f 100644
--- a/modules/31-advanced-strings/25-interpolation/es/README.md
+++ b/modules/31-advanced-strings/25-interpolation/es/README.md
@@ -1,9 +1,84 @@
-La concatenación funciona, pero los template literals son más claros.
+
+Recordemos cómo funciona la concatenación. Para ello unimos las cadenas necesarias (o las variables con cadenas dentro) mediante el signo `+`:
+
+```javascript
+const firstName = 'Joffrey';
+const greeting = 'Hello';
+
+console.log(greeting + ', ' + firstName + '!');
+// => Hello, Joffrey!
+```
+
+Pero en expresiones complejas cuesta ver de inmediato qué texto se obtendrá al final. Sobre todo si en la cadena hay espacios, comas o comillas: empiezan a estorbar la lectura. Incluso el ejemplo actual exige un pequeño esfuerzo para entender cuál será el resultado.
+
+Por esa razón, en muchos lenguajes existe una operación llamada interpolación. La interpolación es una forma de insertar los valores de las variables directamente dentro de una cadena. En JavaScript, para eso se usan las **plantillas de cadena** (template literals). Se escriben entre comillas invertidas `` ` ``, y las variables se insertan con `${}`:
```javascript
-const greeting = 'Hola';
-const firstName = 'Ana';
+const firstName = 'Joffrey';
+const greeting = 'Hello';
console.log(`${greeting}, ${firstName}!`);
-// => Hola, Ana!
+// => Hello, Joffrey!
```
+
+Las comillas invertidas indican que dentro de la cadena se pueden usar variables. Sus nombres se escriben en `${}`, y JavaScript sustituye automáticamente los valores necesarios.
+
+```text
+firstName = 'Joff'
+greeting = 'Hello'
+
+`${greeting}, ${firstName}!`
+ └───┬───┘ └────┬────┘
+ 'Hello' 'Joff'
+ └──────┬────────┘
+ 'Hello, Joff!'
+```
+
+Compara estos dos ejemplos uno al lado del otro:
+
+```javascript
+console.log(greeting + ', ' + firstName + '!');
+console.log(`${greeting}, ${firstName}!`);
+```
+
+La segunda variante es más simple y más clara.
+
+## Cómo funciona
+
+Todo lo que está dentro de `${}` se evalúa como una expresión de JavaScript, y el resultado se inserta en la cadena. Por eso dentro se pueden usar no solo variables, sino cualquier expresión: aritmética, llamadas a funciones y así sucesivamente.
+
+```javascript
+const price = 100;
+const count = 3;
+
+console.log(`Total: ${price * count}`);
+// => Total: 300
+```
+
+## Las comillas invertidas son la clave
+
+Una plantilla de cadena se escribe **obligatoriamente** entre comillas invertidas `` ` ``. Las comillas simples o dobles no funcionan para la interpolación:
+
+```javascript
+console.log('${firstName}'); // mostrará literalmente: ${firstName}
+console.log(`${firstName}`); // mostrará el valor de la variable
+```
+
+## Ejemplo
+
+```javascript
+const school = 'Hexlet';
+
+const whatIsIt = `${school} - online courses`;
+console.log(whatIsIt); // => Hexlet - online courses
+```
+
+Esa forma de escribir se lee con facilidad: los espacios, los guiones y los símbolos se ven de inmediato. La cadena se parece exactamente a como aparecerá en la salida. Eso hace que el código sea claro y cómodo de mantener.
+
+## Por qué esto importa
+
+La interpolación es preferible a la concatenación en casi todos los lenguajes de programación modernos. Ella:
+
+- simplifica la estructura de las cadenas;
+- mejora la legibilidad del código;
+- reduce la cantidad de errores al trabajar con espacios y signos de puntuación.
diff --git a/modules/31-advanced-strings/30-symbols/es/README.md b/modules/31-advanced-strings/30-symbols/es/README.md
index 3552cd44..a985cd1b 100644
--- a/modules/31-advanced-strings/30-symbols/es/README.md
+++ b/modules/31-advanced-strings/30-symbols/es/README.md
@@ -1,6 +1,91 @@
-Accede a caracteres individuales con notación de corchetes e índice base cero.
+A veces hace falta obtener un solo carácter de una cadena. Por ejemplo, si el sitio conoce el nombre y el apellido del usuario y hay que mostrarlos en formato abreviado, del tipo `A. Ivanov`. Para eso se necesita tomar la primera letra del nombre.
+
+En JavaScript, para acceder a los caracteres de una cadena se usa la indexación. La indexación significa que cada carácter de la cadena tiene su propio número, es decir, su índice. La indexación empieza en cero: el primer carácter tiene el índice `0`, el segundo el `1` y así sucesivamente. Imaginemos que tenemos una cadena:
+
+```javascript
+const firstName = 'Alexander';
+```
+
+Para obtener la primera letra, indicamos su posición (el índice) entre corchetes:
+
+```javascript
+console.log(firstName[0]); // => A
+```
+
+Los índices en JavaScript (y en muchos lenguajes) empiezan en cero:
+
+```text
+Carácter A l e x a n d e r
+Índice 0 1 2 3 4 5 6 7 8
+```
+
+La longitud de la cadena `Alexander` es `9`, por eso el índice del último carácter es `8`, es decir, `9 - 1`. La longitud de una cadena se puede averiguar con la función `length()`:
+
+```javascript
+import { length } from 'hexlet-basics/string';
+
+console.log(length(firstName)); // => 9
+console.log(firstName[length(firstName) - 1]); // => r
+```
+
+La línea `import` al principio del archivo conecta la función didáctica `length()` de la biblioteca: hay que copiarla tal cual. Cómo están hechas las importaciones lo veremos en las lecciones sobre módulos.
+
+Si cambia la longitud de la cadena, el último carácter también se desplaza y habrá que volver a calcular su índice.
+
+## Salirse de los límites de la cadena
+
+A diferencia de algunos lenguajes, en JavaScript acceder a un índice que no existe no provoca un error: se devuelve un valor especial, `undefined`. Es el «aquí no hay nada» del mundo de JavaScript; lo veremos en detalle en el módulo sobre tipos de datos.
+
+```javascript
+console.log(firstName[9]); // => undefined
+```
+
+Por eso, en programación se acostumbra a comprobar la longitud de la cadena y acceder a sus caracteres solo cuando es seguro. Llegaremos a eso en lecciones futuras.
+
+## Extraer caracteres desde el final
+
+En algunos lenguajes (por ejemplo, en Python) para acceder a los caracteres desde el final se usan índices negativos. En JavaScript los corchetes **no** entienden los índices negativos: `firstName[-1]` devolverá `undefined`. Por eso el índice de un carácter contado desde el final se calcula a través de la longitud de la cadena:
+
+```javascript
+import { length } from 'hexlet-basics/string';
+
+const word = 'Hexlet';
+
+console.log(word[length(word) - 1]); // => t, el último carácter
+console.log(word[length(word) - 2]); // => e, el penúltimo carácter
+```
+
+```text
+Cadena: 'H' 'e' 'x' 'l' 'e' 't'
+Índice: 0 1 2 3 4 5
+```
+
+Aquí `length(word)` es igual a `6`, por eso el último carácter tiene el índice `length(word) - 1`, es decir, `5`. Este enfoque funciona correctamente incluso si la cadena cambia de longitud.
+
+El índice se puede guardar en una variable:
```javascript
-const word = 'hola';
-console.log(word[0]); // => h
+const index = 0;
+console.log(word[index]); // => H
+```
+
+Este enfoque es útil cuando el índice se calcula en algún lugar del código y después se usa para acceder al carácter necesario.
+
+## Caracteres especiales
+
+En la indexación se cuentan las letras normales, los signos y los caracteres especiales. Todos ocupan una posición en la cadena y tienen su índice, aunque «no se vean» en la pantalla.
+
+Por ejemplo, en la cadena `'\nyou'` el primer carácter es `\n` (el salto de línea), y en el índice `1` ya está la letra `y`. Por eso el acceso `magic[1]` devolverá precisamente `y`.
+
+## Piensa: ¿qué mostrará este código?
+
+```javascript
+const magic = '\nyou';
+console.log(magic[1]); // => ?
+```
+
+La salida será:
+
+```text
+y
```
diff --git a/modules/31-advanced-strings/70-slices/es/EXERCISE.md b/modules/31-advanced-strings/70-slices/es/EXERCISE.md
index 59369ced..5ad29914 100644
--- a/modules/31-advanced-strings/70-slices/es/EXERCISE.md
+++ b/modules/31-advanced-strings/70-slices/es/EXERCISE.md
@@ -1 +1,7 @@
-Dada `url = 'https://hexlet.io'`, extrae e imprime el dominio sin el protocolo.
+Dada la constante `url = 'https://hexlet.io'`. Extrae y muestra en pantalla el nombre de dominio sin el protocolo:
+
+```text
+hexlet.io
+```
+
+Usa el método `slice()`.
diff --git a/modules/31-advanced-strings/70-slices/es/README.md b/modules/31-advanced-strings/70-slices/es/README.md
index fba3c643..c6c90281 100644
--- a/modules/31-advanced-strings/70-slices/es/README.md
+++ b/modules/31-advanced-strings/70-slices/es/README.md
@@ -1,7 +1,111 @@
-Usa `slice()` para extraer parte de una cadena.
+Al trabajar con cadenas nos encontramos a menudo con una tarea: extraer una parte de la cadena. Por ejemplo, obtener el año de una fecha, el nombre de un nombre completo o los primeros caracteres de una dirección de correo electrónico. Para esos casos, JavaScript tiene una herramienta cómoda: el método `slice()`.
+
+## ¿Qué es una subcadena?
+
+Una subcadena es una parte de una cadena, algo que está contenido dentro de otra cadena. Por ejemplo, en la cadena `'12-08-2034'` una subcadena puede ser `'2034'`, `'12'` o incluso `'-'`. Todo depende de qué información necesitemos extraer.
+
+Supongamos que tenemos una cadena con la fecha `'12-08-2034'`. Queremos obtener de ella solo el año, `'2034'`. En esta cadena cada carácter tiene un índice (una posición), empezando por cero:
+
+```text
+'1' '2' '-' '0' '8' '-' '2' '0' '3' '4'
+ 0 1 2 3 4 5 6 7 8 9
+```
+
+El año empieza en el índice 6 y termina en el 9. Para extraerlo usamos `slice()`:
+
+```javascript
+const value = '12-08-2034';
+const year = value.slice(6, 10);
+console.log(year); // => 2034
+```
+
+La forma de escribir «valor, punto, nombre» es una llamada a un método; qué son los métodos lo veremos en la lección sobre objetos, por ahora basta con usar `.slice()` siguiendo el ejemplo.
+
+La llamada `value.slice(6, 10)` toma los caracteres desde el índice 6 hasta el 9 inclusive. El formato:
+
+```text
+cadena.slice(inicio, fin)
+```
+
+El carácter cuyo índice se indica como «fin» no se incluye. Se puede entender como el número del carácter ante el cual hay que detenerse.
+
+```javascript
+const value = 'code-basics';
+
+console.log(value.slice(5, 11)); // => basics (del índice 5 al 10)
+console.log(value.slice(0, 7)); // => code-ba (del índice 0 al 6)
+console.log(value.slice(2, 6)); // => de-b
+```
+
+## El corte devuelve una cadena
+
+`slice()` siempre devuelve una cadena, incluso si dentro solo hay dígitos. Eso significa que el resultado se puede usar como una cadena normal: concatenarlo, mostrarlo, pasarlo a funciones y volver a cortarlo:
+
+```javascript
+const value = '01-12-9873';
+
+const part = value.slice(3, 7); // => 12-9
+console.log(part.slice(0, 2)); // => 12
+```
+
+Primero obtuvimos la subcadena `'12-9'`, y después hicimos de ella un nuevo corte, `'12'`.
+
+## Corte hasta el final o desde el principio
+
+Si no se indica el segundo argumento, `slice()` devolverá todo desde el índice inicial hasta el final de la cadena. Y `slice(0)` o `slice()` sin argumentos devolverá la cadena completa:
```javascript
-const text = 'Hello, World!';
-console.log(text.slice(7)); // => World!
-console.log(text.slice(7, 12)); // => World
+const value = 'Hexlet';
+
+console.log(value.slice(3)); // => let // del carácter 3 al final
+console.log(value.slice(0, 3)); // => Hex // del principio al carácter 3
+console.log(value.slice()); // => Hexlet // la cadena completa
```
+
+## Índices negativos
+
+`slice()` también sabe contar desde el final de la cadena. Para eso se usan índices negativos: `-1` corresponde al último carácter, `-2` al penúltimo y así sucesivamente. Es cómodo cuando no se conoce de antemano la longitud de la cadena, pero hay que tomar la «cola» o la «parte media» respecto al final:
+
+```javascript
+const value = 'Hexlet';
+
+console.log(value.slice(-1)); // => t // el último carácter
+console.log(value.slice(3, -1)); // => le // del 3 al penúltimo
+console.log(value.slice(-3)); // => let // los últimos tres caracteres
+```
+
+## Corte con variables
+
+Los límites del corte no tienen que estar fijados con números. Se pueden usar variables:
+
+```javascript
+const start = 1;
+const end = 5;
+
+const value = 'Hexlet';
+console.log(value.slice(start, end)); // => exle
+```
+
+Esto resulta especialmente útil cuando los límites se calculan durante la ejecución del programa.
+
+## Lo que `slice()` no tiene
+
+En algunos lenguajes (por ejemplo, en Python) el corte tiene un tercer parámetro, el paso, y con él se puede tomar cada segundo carácter o invertir la cadena. El método `slice()` no tiene paso. Ese tipo de tareas en JavaScript se resuelven con bucles y otras herramientas a las que volveremos más adelante.
+
+Existe también un método parecido, `substring()`. Funciona casi como `slice()`, pero no entiende los índices negativos (los trata como `0`), por eso para extraer la «cola» de una cadena resulta más cómodo `slice()`.
+
+## Chuleta rápida
+
+```javascript
+const value = 'Hexlet';
+
+value.slice(); // Hexlet — la cadena completa
+value.slice(0); // Hexlet
+value.slice(5); // t
+value.slice(0, 5); // Hexle
+value.slice(-1); // t — el último carácter
+value.slice(-3); // let — los últimos tres caracteres
+value.slice(2, -1); // xle — del tercero al penúltimo
+```
+
+No te preocupes si ahora no memorizas todas las combinaciones: empezarás a usarlas en la práctica muy pronto. Lo principal es entender la estructura básica `cadena.slice(inicio, fin)`.
diff --git a/modules/31-advanced-strings/90-multiline-strings/es/EXERCISE.md b/modules/31-advanced-strings/90-multiline-strings/es/EXERCISE.md
index 69868613..6f7765a9 100644
--- a/modules/31-advanced-strings/90-multiline-strings/es/EXERCISE.md
+++ b/modules/31-advanced-strings/90-multiline-strings/es/EXERCISE.md
@@ -1,4 +1,4 @@
-Crea una variable `email` con texto multilínea e imprímelo:
+Crea una variable `email` con texto multilínea y muéstrala en pantalla:
```text
Dear customer!
@@ -6,3 +6,5 @@ Dear customer!
Your order has been accepted.
Expected delivery: 3 business days.
```
+
+Usa una plantilla de cadena (comillas invertidas).
diff --git a/modules/31-advanced-strings/90-multiline-strings/es/README.md b/modules/31-advanced-strings/90-multiline-strings/es/README.md
index 1104e868..c00d508d 100644
--- a/modules/31-advanced-strings/90-multiline-strings/es/README.md
+++ b/modules/31-advanced-strings/90-multiline-strings/es/README.md
@@ -1,6 +1,115 @@
-Los template literals preservan los saltos de línea naturalmente.
+A veces el texto de un programa tiene que estar formado por varias líneas. Por ejemplo, al generar un correo, al crear una plantilla, al formatear un mensaje de error o simplemente al trabajar con textos largos.
+
+Por supuesto, se puede usar el carácter de salto de línea `\n`, como hacíamos antes:
+
+```javascript
+const text = 'Un ejemplo de texto,\nformado por\nvarias líneas';
+```
+
+Al imprimirla, la cadena se verá así:
+
+```text
+Un ejemplo de texto,
+formado por
+varias líneas
+```
+
+Pero esa forma resulta incómoda, sobre todo si la cadena es larga o si hay que añadir saltos nuevos a menudo. Cada `\n` hay que insertarlo a mano, y eso empeora la legibilidad del código.
+
+## Las cadenas multilínea como alternativa
+
+En JavaScript existe una forma más cómoda de escribir texto en varias líneas: las plantillas de cadena (template literals). Se escriben entre comillas invertidas `` ` ``, y todos los saltos de línea que haya dentro se conservan literalmente:
+
+```javascript
+const text = `Un ejemplo de texto,
+formado por
+varias líneas`;
+```
+
+Ahora en el código todo se ve igual que en la salida:
+
+```text
+Un ejemplo de texto,
+formado por
+varias líneas
+```
+
+Cada salto en el código fuente se convierte en un carácter `\n` dentro de la cadena.
+
+## Cuidado con la línea vacía al final
+
+Donde pongas la comilla invertida de cierre, ahí terminará el texto. Si la pasas a una línea nueva, ese salto también entrará en el resultado:
+
+```javascript
+const text = `Un ejemplo de texto,
+formado por
+varias líneas
+`;
+
+console.log('====');
+console.log(text);
+console.log('====');
+```
+
+La salida:
+
+```text
+====
+Un ejemplo de texto,
+formado por
+varias líneas
+
+====
+```
+
+Fíjate: aparece una línea vacía al final. Para evitarla, no pases la comilla de cierre a una línea nueva:
```javascript
-const text = `Línea 1
-Línea 2`;
+const text = `Un ejemplo de texto,
+formado por
+varias líneas`;
```
+
+## Ventajas de las cadenas multilínea
+
+- Legibilidad del código: el texto en el código se ve casi como en la pantalla.
+- Comodidad al editar: es fácil añadir, borrar y cambiar líneas.
+- No hace falta escapar las comillas de dentro:
+
+```javascript
+const quote = `Aquí no hay que escapar ni las comillas 'simples' ni las "dobles"`;
+```
+
+## Interpolación dentro de una cadena multilínea
+
+Las plantillas de cadena combinan la multilínea y la interpolación, así que dentro se pueden sustituir valores de variables mediante `${}`:
+
+```javascript
+const a = 'A';
+const b = 'B';
+
+const text = `${a} y ${b}
+en líneas distintas`;
+```
+
+La salida:
+
+```text
+A y B
+en líneas distintas
+```
+
+Esto resulta especialmente cómodo para plantillas, correos, mensajes de error y descripciones multilínea.
+
+## Cuidado con la sangría
+
+Las sangrías del código entran en la cadena. Si haces una sangría dentro de una plantilla de cadena, aparecerá en el texto:
+
+```javascript
+const message = `Hello
+ World`; // la cadena contiene 2 espacios antes de World
+```
+
+## El ordenador y la persona perciben el código de forma distinta
+
+JavaScript procesará igual una cadena con `\n` y una cadena multilínea: para el motor son lo mismo. Pero para la persona que lee el código, las cadenas multilínea son mucho más cómodas y claras.
diff --git a/modules/33-data-types/52-data-types-immutability/es/README.md b/modules/33-data-types/52-data-types-immutability/es/README.md
index 20302a79..acd48118 100644
--- a/modules/33-data-types/52-data-types-immutability/es/README.md
+++ b/modules/33-data-types/52-data-types-immutability/es/README.md
@@ -1,20 +1,65 @@
+Imaginemos que tenemos una cadena y queremos reemplazar en ella un carácter, por ejemplo la primera letra de un nombre:
-¿Qué sucede si intentamos cambiar un carácter en una cadena de texto?
+```javascript
+let greeting = 'Hello';
+greeting[0] = 'J';
+console.log(greeting); // => Hello (¡no cambió!)
+```
+
+A diferencia de algunos lenguajes, donde ese intento provoca un error, en JavaScript la asignación por índice simplemente **se ignora en silencio**: la cadena no cambia (y en modo estricto eso provocará un error `TypeError`). La razón es una: las cadenas en JavaScript no se pueden modificar por partes. Una vez creadas, pasan a ser inmutables.
+
+## ¿Por qué las cadenas son inmutables?
+
+Los tipos primitivos (cadenas, números, valores lógicos) en JavaScript no se pueden modificar. Eso da ventajas importantes:
+
+- Seguridad: los valores no cambiarán por accidente.
+- Rendimiento: con valores inmutables es más simple trabajar dentro del motor.
+- Previsibilidad: menos efectos inesperados al pasar datos a funciones.
+
+## ¿Y entonces cómo se «cambia» una cadena?
+
+Si hace falta «cambiar» una cadena, se crea una nueva a partir de la anterior y se guarda en la misma variable. Por ejemplo, reemplacemos la primera letra:
+
+```javascript
+const word = 'hello';
+const fixed = 'H' + word.slice(1);
+console.log(fixed); // => Hello
+```
+
+```text
+word = 'hello'
+
+word[0] = 'H' → no pasa nada, las cadenas son inmutables
+
+'H' + word.slice(1)
+└────────┬────────┘
+ 'Hello' ← se creó una cadena nueva
+```
+
+Reasignar la variable por completo también se puede, pero eso crea una cadena **nueva**, no modifica la anterior:
```javascript
-let firstName = 'Alexander';
-// El código se ejecutará sin errores
-firstName[0] = 'B';
-console.log(firstName); // => Alexander
+let greeting = 'Hello';
+greeting = 'Jello';
+console.log(greeting); // => Jello
```
-Sorprendentemente, el valor de la variable `firstName` permanecerá igual, aunque el código se ejecute sin errores. Esto se debe a la inmutabilidad de los tipos primitivos en JavaScript: el lenguaje no proporciona ninguna forma física de cambiar una cadena de texto. La inmutabilidad de los tipos primitivos es importante por varias razones, siendo la principal la eficiencia. Pero, ¿qué hacer si realmente necesitamos cambiarla? Para eso existen las variables:
+## ¿Una variable nueva o la misma?
+
+Vale la pena reutilizar una variable solo cuando se trata de una misma entidad. Si ya son otros datos, es mejor declarar una variable aparte:
```javascript
-let firstName = 'Alexander';
-// El código se ejecutará sin errores
-firstName = 'Blexander'
-console.log(firstName); // => Blexander
+// La misma cadena, simplemente la actualizamos
+let name = 'Alexander';
+name = 'Blexander';
+
+// Entidades distintas: mejor variables distintas
+const firstName = 'Alexander';
+const correctedFirstName = 'Blexander';
```
-Existe una gran diferencia entre cambiar el valor de una variable y cambiar el valor en sí. No se puede cambiar los tipos primitivos en JavaScript (pero sí se pueden cambiar los tipos compuestos; más información sobre ellos en Hexlet), aunque reemplazar el valor de una variable no presenta problemas.
+Intentar «meter» todas las cadenas en una sola variable enreda el código: la variable deja de decir qué guarda.
+
+## Conclusión
+
+Los tipos de datos primitivos en JavaScript (cadenas, números, valores lógicos) son inmutables. Eso significa que, una vez creados, su valor no se puede cambiar. Cambiar un solo carácter de una cadena es imposible: cualquier «cambio» ocurre creando un valor nuevo y redefiniendo la variable.
diff --git a/modules/33-data-types/55-data-types-casting/es/EXERCISE.md b/modules/33-data-types/55-data-types-casting/es/EXERCISE.md
index fc9730bd..facc6438 100644
--- a/modules/33-data-types/55-data-types-casting/es/EXERCISE.md
+++ b/modules/33-data-types/55-data-types-casting/es/EXERCISE.md
@@ -1 +1,5 @@
-Dada `temperature = 36.6`, trunca la parte decimal, convierte a cadena e imprime `36 °C`.
+Dada la constante `temperature = 36.6`. Escribe un programa que:
+
+1. Descarte la parte decimal (`Math.trunc()`).
+2. Convierta el resultado en cadena (`String()`).
+3. Muestre la cadena con la unidad de medida: `36 °C`.
diff --git a/modules/33-data-types/55-data-types-casting/es/README.md b/modules/33-data-types/55-data-types-casting/es/README.md
index 5d6adbab..c90d41cb 100644
--- a/modules/33-data-types/55-data-types-casting/es/README.md
+++ b/modules/33-data-types/55-data-types-casting/es/README.md
@@ -1,6 +1,74 @@
-Usa funciones de conversión para cambiar el tipo de un valor.
+En los programas reales surge a menudo la situación de que hay que convertir datos de un tipo en otro. Esto es especialmente relevante al procesar la entrada del usuario o los datos de los formularios web: allí todo llega en forma de cadenas, aunque hayas introducido un número.
+
+JavaScript sabe convertir tipos automáticamente (conversión implícita), pero confiar en eso es peligroso. Por eso, cuando sabes exactamente qué tipo quieres obtener, es mejor convertir el valor de forma **explícita**: para ello existen funciones especiales.
+
+## Convertir una cadena en número
+
+Imaginemos que recibimos de un formulario la cadena `'345'` y necesitamos sumar ese número con otro:
+
+```javascript
+const number = Number('345');
+console.log(number + 5); // => 350
+```
+
+La función `Number()` recibe una cadena y la convierte en número. Esas funciones se llaman funciones de conversión de tipo (casting functions).
+
+```javascript
+console.log(Number('0')); // => 0
+console.log(Number('10')); // => 10
+console.log(Number('3.14')); // => 3.14
+console.log(Number('hello')); // => NaN (no se pudo convertir)
+```
+
+Además de `Number()`, existen las funciones `parseInt()` y `parseFloat()`: «extraen» de la cadena un número entero o decimal y saben ignorar los caracteres de sobra al final:
+
+```javascript
+console.log(parseInt('10px')); // => 10
+console.log(parseFloat('3.5kg')); // => 3.5
+```
+
+## Convertir en cadena con String()
+
+Si hace falta convertir un número o un valor lógico en cadena, usa la función `String()`:
+
+```javascript
+console.log(String(10)); // => '10'
+console.log(String(true)); // => 'true'
+console.log(String(3.5)); // => '3.5'
+```
+
+Esto es útil al construir textos y mensajes:
```javascript
-Number('42'); // => 42
-String(42); // => '42'
+const age = 42;
+console.log('Age: ' + String(age)); // => Age: 42
+// Aunque aquí resulta más cómoda la interpolación: `Age: ${age}`
```
+
+Las conversiones se pueden hacer una tras otra: el valor recorre una cadena de transformaciones:
+
+```text
+'123' ──Number()──→ 123 ──String()──→ '123'
+```
+
+## Convertir en valor lógico con Boolean()
+
+```javascript
+console.log(Boolean(0)); // => false
+console.log(Boolean('')); // => false
+console.log(Boolean('hello')); // => true
+console.log(Boolean(1)); // => true
+```
+
+## Descartar la parte decimal con Math.trunc()
+
+`Math.trunc()` es una función incorporada; las llamadas a funciones se analizan en detalle en el módulo siguiente, por ahora basta con usarla siguiendo el ejemplo.
+
+A veces hay que obtener un entero a partir de un número decimal, descartando la parte decimal. Para eso se usa `Math.trunc()`:
+
+```javascript
+console.log(Math.trunc(36.6)); // => 36
+console.log(Math.trunc(-36.6)); // => -36
+```
+
+A diferencia de `Math.floor()`, `Math.trunc()` simplemente descarta la parte decimal independientemente del signo.
diff --git a/modules/35-calling-functions/135-calling-functions-default-params/es/EXERCISE.md b/modules/35-calling-functions/135-calling-functions-default-params/es/EXERCISE.md
index 6f33090b..213d01d7 100644
--- a/modules/35-calling-functions/135-calling-functions-default-params/es/EXERCISE.md
+++ b/modules/35-calling-functions/135-calling-functions-default-params/es/EXERCISE.md
@@ -1,2 +1,16 @@
+En el código se han definido datos sobre un viaje en automóvil: la distancia, el consumo de combustible, el precio del combustible y la cantidad de pasajeros.
-Redondea el número almacenado en la constante `number` a dos decimales y muestra el resultado en pantalla.
+Calcula y muestra en pantalla tres valores, cada uno en una línea aparte:
+
+1. El volumen de combustible en litros necesario para el viaje. Redondéalo a un decimal con `toFixed(1)`.
+2. El costo total del viaje. Redondéalo a dos decimales con `toFixed(2)`.
+3. El costo del viaje para cada pasajero. Redondéalo a entero llamando a `toFixed()` sin argumento (el valor por defecto es 0 decimales).
+
+```text
+distance ──────┐
+ ├──→ fuel ──────┐
+fuelConsumption ┘ ├──→ tripCost ──────┐
+ │ ├──→ perPerson
+fuelPrice ─────────────────────┘ │
+passengers ─────────────────────────────────────────┘
+```
diff --git a/modules/35-calling-functions/135-calling-functions-default-params/es/README.md b/modules/35-calling-functions/135-calling-functions-default-params/es/README.md
index 31237f2d..926d4e01 100644
--- a/modules/35-calling-functions/135-calling-functions-default-params/es/README.md
+++ b/modules/35-calling-functions/135-calling-functions-default-params/es/README.md
@@ -1,23 +1,52 @@
+Algunas funciones tienen **parámetros opcionales**. Eso significa que para ellos se ha fijado de antemano un valor por defecto, y al llamar a la función ese parámetro se puede omitir.
-Veamos la función `round()`, que redondea un número entero:
+Veamos el método `toFixed()`, que redondea un número a una cantidad dada de decimales. `toFixed()` es un método, es decir, una función adjunta a un valor y llamada mediante el punto; los métodos los veremos en detalle en la lección sobre objetos.
```javascript
-const result = round(10.25, 0); // 10
+const result = (10.25).toFixed(1); // => '10.3'
```
-Le pasamos dos parámetros: el número que queremos redondear y la precisión de redondeo. Un valor de `0` significa que se redondeará al número entero más cercano, es decir, se descarta la parte decimal.
+Fíjate en las comillas del resultado: `toFixed()` devuelve una **cadena**, no un número, por eso no se puede usar directamente en cálculos posteriores.
-En la mayoría de los casos, queremos redondear al número entero (no a los décimos, por ejemplo), por lo que los creadores de la función `round()` hicieron el segundo parámetro **opcional** y le dieron un valor por defecto de `0`. Esto significa que no es necesario especificar el segundo parámetro y el resultado será el mismo:
+Le pasamos un valor: la precisión del redondeo (1 decimal). Pero ese parámetro es opcional. Si no se indica, se usa el valor por defecto `0`, es decir, el redondeo a entero:
```javascript
-const result = round(10.25); // 10
+console.log((10.25).toFixed()); // => '10'
```
-Si necesitamos una precisión distinta, podemos pasar un parámetro:
+Si hace falta otra precisión, se indica de forma explícita:
```javascript
-// redondeo a un decimal
-const result = round(10.25, 1); // 10.3
+console.log((3.14159).toFixed(2)); // => '3.14'
+console.log((3.14159).toFixed(4)); // => '3.1416'
```
-Si una función en JavaScript tiene parámetros opcionales, siempre se colocan después de los parámetros obligatorios. Pueden ser cualquier cantidad (dependiendo de la función en sí), pero siempre van juntos y al final de la lista de argumentos.
+```text
+(10.25).toFixed(1) → argumento: 1 → '10.3'
+(10.25).toFixed() → argumento: (0) → '10'
+ └── valor por defecto
+```
+
+La cantidad de parámetros opcionales depende de cada función, pero los obligatorios van siempre antes de los opcionales.
+
+## La firma de una función
+
+Cada función tiene una **firma**: la descripción de su nombre, sus parámetros y el orden en que se usan. La firma ayuda a entender qué datos espera la función y qué ocurrirá si los parámetros no se indican.
+
+En la documentación, los parámetros opcionales se muestran a menudo entre corchetes. Por ejemplo, la firma de `toFixed`:
+
+```text
+toFixed([digits])
+```
+
+Aquí `digits` es la cantidad de decimales. Los corchetes significan que el parámetro es opcional; si no se indica, por defecto será `0`.
+
+## Cómo trabajar con funciones nuevas
+
+Cuando te encuentras con una función nueva, resulta cómodo seguir un patrón simple:
+
+1. Abrir la documentación (por ejemplo, MDN) y buscar la firma de la función.
+2. Mirar los ejemplos de uso.
+3. Abrir la consola del navegador o de Node.js y probar a llamar a la función con distintos argumentos.
+
+Este enfoque ayuda a entender rápidamente qué parámetros de la función son obligatorios y cuáles opcionales, y qué resultados devuelve.
diff --git a/modules/38-objects/100-objects/es/README.md b/modules/38-objects/100-objects/es/README.md
index 32b2e187..4ee8dc7c 100644
--- a/modules/38-objects/100-objects/es/README.md
+++ b/modules/38-objects/100-objects/es/README.md
@@ -1,17 +1,17 @@
-JavaScript admite la programación orientada a objetos (POO): de forma muy simplificada, es un enfoque en el que operamos no con datos y funciones, sino con objetos y métodos. No nos detendremos en detalle en este tema en este curso, porque es amplio y requiere cierta preparación. Pero no podemos ignorarlo por completo, porque los objetos aparecen en JavaScript casi de inmediato. Así que lo abordaremos solo en la medida en que lo requieran las tareas actuales.
+JavaScript admite la programación orientada a objetos (POO): de forma muy simplificada, es un enfoque en el que operamos no con datos y funciones, sino con objetos y métodos. No pensamos detenernos en detalle en este tema en este curso, porque es amplio y su comprensión requiere cierto nivel de preparación. Ignorarlo por completo es imposible, porque los objetos aparecen literalmente de inmediato, en cuanto empezamos a escribir código en JavaScript. Por eso lo abordaremos, pero solo en la medida necesaria para las tareas actuales.
-Hasta ahora trabajábamos con datos y les aplicábamos funciones. En la POO, en lugar de datos tenemos objetos sobre los que se llaman métodos. Por ejemplo, las cadenas en JavaScript son objetos y tienen un método `toUpperCase()` que convierte todas las letras a mayúsculas.
+Hasta este momento trabajábamos con datos y les aplicábamos funciones. En la POO, en lugar de datos tenemos objetos sobre los que se llaman métodos. Por ejemplo, las cadenas en JavaScript son objetos y tienen un método `toUpperCase()`, que convierte todas las letras a mayúsculas.
```javascript
const name = 'Robb';
console.log(name.toUpperCase()); // => ROBB
```
-A diferencia de las funciones, los métodos se llaman *sobre un objeto*. Primero se escribe el objeto (un valor, una variable o una constante), luego un punto y la llamada al método.
+A diferencia de las funciones, los métodos se llaman *sobre un objeto*. Primero se escribe el objeto (un valor, una variable o una constante), y luego, después de un punto, la llamada al método. Aunque el método `toUpperCase()` no recibe argumentos, por dentro sabe sobre qué objeto se lo llama y tiene acceso al objeto mismo.
## Propiedades
-Además de los métodos, los datos tienen propiedades. Una propiedad es un valor asociado a los datos, al que se accede con un punto después de la variable (o constante). Por ejemplo, las cadenas tienen una longitud: la propiedad `length`:
+Además de los métodos, los datos tienen propiedades. Una propiedad es un valor asociado a los datos, al que se accede con un punto justo después de la variable o la constante. Por ejemplo, las cadenas tienen una longitud: la propiedad `length`:
```javascript
const name = 'Robb';
@@ -19,59 +19,135 @@ const len = name.length;
console.log(len); // => 4
```
-En muchos lenguajes la longitud de una cadena se calcula con una función especial, pero en JavaScript las propiedades están incorporadas directamente en el lenguaje. Las propiedades están asociadas a los datos de los que se obtienen. Para los tipos de datos primitivos, todas las propiedades están documentadas, como por ejemplo, las [cadenas de texto](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/String). Sin embargo, los números no tienen propiedades.
+En los módulos anteriores, para obtener la longitud de una cadena usábamos la función didáctica `length()` de la biblioteca `hexlet-basics/string`:
-JavaScript permite acceder a propiedades que no existen (por ejemplo, debido a errores de escritura). En este caso, el valor de esas propiedades es `undefined`:
+```javascript
+import { length } from 'hexlet-basics/string';
+
+const name = 'Robb';
+console.log(length(name)); // => 4
+```
+
+Era un reemplazo temporal: en muchos lenguajes la longitud de una cadena se calcula realmente mediante una función especial. En JavaScript, en cambio, la longitud está incorporada directamente en el lenguaje como la propiedad `.length`. A partir de esta lección la función didáctica ya no hará falta: en todas partes usamos `.length`.
+
+Las propiedades están asociadas a los datos de los que se obtienen. Para los tipos primitivos, todas las propiedades están descritas en la documentación, como por ejemplo en las [cadenas](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/String). Los números, en cambio, no tienen propiedades.
+
+JavaScript permite acceder a propiedades que no existen (por ejemplo, por errores de escritura). En ese caso su valor es `undefined`:
```javascript
const name = 'Robb';
console.log(name.whatIsThat); // => undefined
```
-*Pregunta de autoevaluación. ¿Qué imprimirá el código `console.log(name[name.length])` para `name`, definido anteriormente? ¿Por qué es esa la respuesta?*
+*Pregunta de autoevaluación. ¿Qué imprimirá el código `console.log(name[name.length])` para el `name` definido más arriba? ¿Por qué es esa la respuesta?*
Respuesta
-El código imprimirá `undefined`, porque se está accediendo a un índice que está fuera de los límites de la cadena. En este caso, `name.length` es 4, pero el índice del último carácter en la cadena es 3.
+El código imprimirá `undefined`, porque se está accediendo a un índice que queda fuera del límite de la cadena. En este caso `name.length` es 4, y el índice del último carácter de la cadena es 3.
-## Métodos
+## Métodos de las cadenas
-Además de las propiedades, los datos también tienen métodos, los cuales son funciones que se encuentran dentro de las propiedades. Desde un punto de vista práctico, esto significa que un método funciona y se llama como una función, pero se accede a él como una propiedad, a través de un punto.
+Los datos suelen tener bastantes más métodos que propiedades. Las cadenas tienen varias docenas; estos son algunos de ellos.
```javascript
-const name = 'Robb';
-const upperName = name.toUpperCase();
-console.log(upperName); // => ROBB
+// Convertir todas las letras a mayúsculas
+console.log('hexlet'.toUpperCase()); // => HEXLET
+
+// Convertir todas las letras a minúsculas
+console.log('HeXleT'.toLowerCase()); // => hexlet
+
+// Eliminar los espacios al principio y al final de la cadena
+console.log(' hi '.trim()); // => hi
```
-Los métodos incorporados siempre operan en los datos con los que están asociados. El método `.toUpperCase()` devuelve la misma cadena, pero convierte todos los caracteres a mayúsculas. Por lo general, hay muchos más métodos que propiedades para los datos, por ejemplo, para las cadenas hay [varias docenas](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/String). A primera vista, en la documentación se describen de manera un poco extraña: *String.prototype.toLowerCase()*. Esta descripción revela algunos detalles internos de implementación que no son importantes en este momento, y tampoco hemos estudiado toda la base necesaria para hablar sobre los prototipos.
+Algunos métodos reciben parámetros. Por ejemplo, en el método `replace()` el primer parámetro contiene la subcadena que hay que reemplazar, y el segundo la cadena de reemplazo.
-Los números también tienen métodos, como se muestra en [este enlace](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Number):
+```javascript
+const text = 'abracadabra';
+
+// Se reemplaza solo la primera aparición
+console.log(text.replace('a', 'o')); // => obracadabra
+console.log(text.replace('abra', '!')); // => !cadabra
+```
+
+En JavaScript hay realmente muchos métodos, y no se aprenden de memoria. Normalmente los programadores, en el transcurso del trabajo, recuerdan qué operaciones necesitan y cómo se llaman aproximadamente esos métodos. Cuando surge una tarea, o recuerdan el método adecuado, o lo encuentran rápido en la documentación.
+
+## Los números también tienen métodos
```javascript
const temperature = 22.93;
-// Redondear a un decimal
+// Redondeo a un decimal
const roundedTemperature = temperature.toFixed(1);
// El método devuelve una cadena que contiene el número convertido
console.log(roundedTemperature); // => 22.9
-// También se puede llamar directamente así
+// Directamente se puede llamar así
// Los paréntesis son obligatorios, de lo contrario no funcionará
(22.93).toFixed(1); // 22.9
```
-*Nota para la anfitriona. Técnicamente, todo es un poco más complicado. Los métodos no están en los números en sí, sino en los datos (objetos) del tipo Number. Los números que se asignan a variables o constantes se convierten automáticamente a este tipo cuando se accede a ellos, en este momento se produce lo que se llama boxing.*
+*Nota al margen. Técnicamente todo es algo más complicado. Los métodos no están en los números en sí, sino en los datos (objetos) del tipo Number. Los números guardados en variables o constantes se convierten automáticamente a ese tipo cuando se accede a ellos; en ese momento ocurre lo que se llama boxing.*
+
+## Método y función: comparación
+
+Desde el punto de vista del código, los métodos y las funciones se comportan de forma parecida. Reciben valores y devuelven un resultado. Se diferencian solo en la **sintaxis** de la llamada.
+
+```javascript
+// Llamada a una función
+Math.min(3, 5);
+
+// Llamada a un método
+'hexlet'.toUpperCase();
+```
+
+La función se llama desde fuera y recibe los argumentos entre paréntesis. El método es una operación incorporada en el valor mismo. Por debajo el valor se pasa hacia dentro, pero eso queda oculto para nosotros.
+
+Surge una pregunta lógica: ¿para qué hacen falta los métodos, por qué no simplemente funciones? Hay dos razones por las que resultó así:
+
+1. Históricamente salió así. JavaScript se desarrolló demasiado rápido, y por eso no todo quedó bien pensado.
+2. No todas las funciones tienen relación con un valor concreto. Tomemos como ejemplo `Math.min()`: encuentra el mínimo entre los números que se le pasan. Hacerla método de un número concreto, por ejemplo `(1).min()`, no es lógico: no está ligada a un número en particular.
+
+Por otro lado, las funciones que trabajan con un valor concreto es lógico implementarlas como métodos, por uniformidad. JavaScript es un lenguaje en el que han arraigado los dos enfoques: se usan activamente tanto las funciones normales como los métodos. Los pros y los contras de estos enfoques se explican en los cursos [dedicados a la POO](https://ru.hexlet.io/programs/js-oop).
+
+## Los métodos devuelven valores
+
+Igual que las funciones, los métodos **devuelven un resultado**. Se pueden usar dentro de expresiones.
+
+```javascript
+const name = 'hexlet';
+console.log(name.toUpperCase() + '!'); // => HEXLET!
+```
+
+Los métodos de las cadenas siempre devuelven una cadena nueva y dejan la original sin cambios. Ese comportamiento se llama inmutabilidad. Hablaremos de ello en la lección siguiente, pero por ahora es importante entender que la cadena queda igual y que el resultado del método es un valor nuevo.
+
+```javascript
+const name = 'hexlet';
+console.log(name.toUpperCase()); // => HEXLET
+console.log(name); // => hexlet
+```
+
+## Propiedades y métodos en las expresiones
-Surge una pregunta lógica: ¿por qué se necesitan métodos en lugar de simplemente funciones? Con los números, la situación es aún más complicada. Algunas operaciones se implementan como métodos de los propios números, por ejemplo, `.toFixed()`, y una gran parte se implementa como métodos disponibles a través de `Math`.
+Las propiedades y los métodos son expresiones igual que las variables, las constantes o las llamadas a funciones. Se pueden usar en operaciones aritméticas y pasar como argumentos a otras funciones.
-Hay dos razones por las que se hace así:
+Uso en operaciones:
-1. Históricamente, JavaScript se desarrolló muy rápido y, por lo tanto, no todo estaba bien pensado originalmente.
-2. No todas las funciones están relacionadas con un valor específico. Tomemos como ejemplo `Math.min()`. Esta función encuentra el número mínimo entre todos los que se le pasan. No tendría sentido hacer que esta función sea un método de un número específico, por ejemplo, así: `(1).min()`. No tiene ninguna relación con un número específico.
+```javascript
+const name = 'Shaya';
+console.log(name.length + 5); // => 10
+console.log(`hi, ${name.toUpperCase()}!`); // => hi, SHAYA!
+```
+
+Uso como argumentos de funciones:
-Por otro lado, las funciones que trabajan con un número específico deben implementarse como métodos para mantener la uniformidad. Un ejemplo de estas funciones es obtener el módulo de un número. En lugar de llamarlo así `Math.abs(-10)`, sería lógico tener esto: `(-10).abs()`.
+```javascript
+const firstName = 'Robb';
+const lastName = 'Shaya';
+// Pasamos las propiedades directamente en la llamada a la función
+console.log(Math.min(firstName.length, lastName.length)); // => 4
+```
-En cuanto a los métodos en general, no todo es tan claro. Hay lenguajes en los que no hay métodos y todo funciona bien; hay lenguajes en los que los métodos son la forma principal de trabajar con funciones, pero incluso en estos lenguajes siempre se utilizan funciones normales junto con los métodos. JavaScript es un lenguaje en el que ambos enfoques han prosperado; se utilizan tanto funciones normales como métodos de manera activa. Los pros y los contras de estos enfoques se explican en detalle en los cursos [dedicados a la POO](https://ru.hexlet.io/programs/js-oop).
+Esto permite escribir código compacto y expresivo, sin guardar los resultados intermedios en variables aparte.
diff --git a/modules/38-objects/200-methods-immutability/es/README.md b/modules/38-objects/200-methods-immutability/es/README.md
index e57416ee..3ca00b0a 100644
--- a/modules/38-objects/200-methods-immutability/es/README.md
+++ b/modules/38-objects/200-methods-immutability/es/README.md
@@ -1,4 +1,3 @@
-
¿Qué se imprimirá en la pantalla en la última llamada?
```javascript
@@ -7,7 +6,36 @@ console.log(name.toUpperCase()); // => TIRION
console.log(name); // => ?
```
-La respuesta a esta pregunta depende de cómo hayas entendido la lección sobre la inmutabilidad de los tipos de datos primitivos. La llamada al método `.toUpperCase()` devuelve un nuevo valor en el que todas las letras están convertidas a mayúsculas, pero no cambia (y no puede hacerlo) la cadena original. Por lo tanto, dentro de la constante (o variable, no importa) se mantendrá el valor antiguo: `'Tirion'`. Esta lógica es válida para los métodos de todos los tipos de datos primitivos. Además, intentar cambiar el valor de una propiedad de estos datos no llevará a nada:
+La respuesta a esta pregunta depende de cómo hayas entendido la lección sobre la inmutabilidad de los tipos de datos primitivos. La llamada al método `.toUpperCase()` devuelve un nuevo valor en el que todas las letras están convertidas a mayúsculas, pero no cambia (y no puede hacerlo) la cadena original. Por lo tanto, dentro de la constante (o variable, no importa) se mantendrá el valor antiguo: `'Tirion'`. Esta lógica es válida para los métodos de todos los tipos primitivos.
+
+## Los métodos no cambian el original
+
+Cuando llamamos a un método de una cadena, parece que la estamos cambiando. En realidad el método **devuelve una cadena nueva**, y el original queda igual:
+
+```javascript
+const text = 'hexlet';
+text.toUpperCase();
+console.log(text); // => hexlet
+```
+
+Para no perder el resultado, hay que guardarlo en una variable:
+
+```javascript
+const text = 'hexlet';
+const upperText = text.toUpperCase();
+console.log(upperText); // => HEXLET
+```
+
+Si no se guarda el resultado del método, simplemente se pierde. Los demás métodos funcionan igual. Por ejemplo, `trim()` devuelve una cadena nueva sin espacios en los extremos, y la original queda igual:
+
+```javascript
+const text = ' hi ';
+const cleaned = text.trim();
+console.log(cleaned); // => 'hi', sin espacios
+console.log(text); // => ' hi ', la cadena no cambió
+```
+
+Más aún, intentar cambiar el valor de una propiedad tampoco lleva a nada:
```javascript
const name = 'Tirion';
@@ -16,10 +44,23 @@ name.length = 100;
console.log(name.length); // => 6
```
-En lugar de cambiar el valor, se puede *reemplazar* el valor. Para ello, se necesitarán variables:
+Está hecho a propósito: los valores primitivos no se pueden modificar después de crearlos. Estropear una cadena por accidente es imposible, y el motor puede reutilizar en memoria las cadenas iguales, ahorrando recursos.
+
+## Reasignar la variable
+
+En lugar de cambiar el valor, se lo puede *reemplazar*. Para eso hace falta una variable (`let`):
```javascript
let name = 'Tirion';
name = name.toUpperCase();
console.log(name); // => TIRION
```
+
+Escribir el resultado de vuelta en la misma variable es apropiado cuando la esencia de los datos no cambia. Después de `trim()` sigue siendo el mismo texto, solo más limpio. Pero si el resultado del método representa otra entidad, es mejor darle un nombre aparte:
+
+```javascript
+const fullName = 'John Doe';
+const headerName = fullName.toUpperCase();
+```
+
+`fullName` es el nombre de una persona, `headerName` es su variante para un encabezado. Son cosas distintas, y guardarlas en una sola variable sería confuso. El nombre de la variable debe reflejar el sentido de los datos que contiene.
diff --git a/modules/38-objects/500-method-chain/es/README.md b/modules/38-objects/500-method-chain/es/README.md
index 16933121..553456fd 100644
--- a/modules/38-objects/500-method-chain/es/README.md
+++ b/modules/38-objects/500-method-chain/es/README.md
@@ -15,7 +15,7 @@ console.log(name.length.toString());
La sintaxis de varios puntos seguidos la vemos por primera vez, pero todas las operaciones que aparecen aquí nos son familiares. Todo lo que sucede en este código es la combinación de capacidades ya conocidas del lenguaje. Esto ocurre bastante a menudo en la programación. Incluso sin conocer la sintaxis, se pueden probar diferentes enfoques y hay una buena probabilidad de que funcionen.
-La forma más sencilla de entender cómo funciona este código es dividir la cadena en operaciones individuales:
+La forma más sencilla de entender cómo funciona este código es dividir la cadena de llamadas en operaciones individuales:
```javascript
const name = 'Tirion';
@@ -23,7 +23,16 @@ const len = name.length;
console.log(len.toString());
```
-Estos ejemplos son completamente equivalentes. Podemos realizar operaciones secuencialmente con la creación intermedia de constantes, o podemos construir una cadena continua de propiedades y métodos. En las cadenas de llamadas, los cálculos siempre se realizan de izquierda a derecha.
+Estos ejemplos son completamente equivalentes. Podemos realizar operaciones secuencialmente con la creación intermedia de constantes, o podemos construir una cadena continua de propiedades y métodos. En las cadenas de llamadas, los cálculos siempre se realizan de izquierda a derecha. Cada método devuelve un valor nuevo, y el método siguiente se aplica ya a ese valor:
+
+```text
+' Hello, World! '.trim().toLowerCase().replace('world', 'js')
+ │ │ │
+ ↓ ↓ ↓
+ 'Hello, World!' │ │
+ 'hello, world!' │
+ 'hello, js!'
+```
Otro ejemplo para reforzar los conocimientos:
@@ -37,7 +46,7 @@ Este tipo de código requiere un poco de esfuerzo mental. Es importante entender
```javascript
const name = 'Tirion';
// ¡Este código no funcionará correctamente!
-console.log(name.toUpperCase.toLowerCase);
+console.log(name.toUpperCase.toLowerCase());
```
Siguiendo esta idea, es posible construir cadenas infinitamente largas (aunque en este caso, inútiles):
@@ -47,4 +56,28 @@ Siguiendo esta idea, es posible construir cadenas infinitamente largas (aunque e
console.log(name.toUpperCase().toLowerCase().length.toString().length);
```
+## La cadena después de un corte
+
+Los métodos se pueden llamar también después de otras operaciones, por ejemplo después de un corte de la cadena:
+
+```javascript
+const text = ' Hello, Hexlet! ';
+// Quitamos los espacios, tomamos una subcadena y pasamos a minúsculas
+console.log(text.trim().slice(7).toLowerCase()); // => hexlet!
+```
+
+Aquí primero se llama a `trim()`, que elimina los espacios. Después se toma el corte `slice(7)`, empezando por el octavo carácter. Y solo después de eso se llama a `toLowerCase()`. Esa forma de escribir se lee de izquierda a derecha y muestra todo el recorrido de transformación de los datos en una sola línea.
+
+## Dónde termina la cadena
+
+La cadena se puede continuar mientras el resultado siga siendo un valor que tenga los métodos necesarios. En cuanto un método o una propiedad devuelve un valor de otro tipo, el conjunto de métodos disponibles cambia:
+
+```javascript
+const text = 'hexlet';
+// .length devuelve un número — ya no tiene métodos de cadena
+console.log(text.length.toUpperCase()); // TypeError: ... is not a function
+```
+
+El número `6`, que devolvió la propiedad `.length`, no sabe hacer `.toUpperCase()`: ese es un método de cadena. En cambio, el número tiene sus propios métodos, por ejemplo `.toString()`, y por eso `text.length.toString()` funciona. Es importante fijarse en qué tipo devuelve cada eslabón de la cadena.
+
*Con las funciones, este truco no funcionará, ya que en su uso normal se anidan unas dentro de otras f(f(f())), lo que dificulta mucho el análisis. Pero esto no significa que no se pueda hacer de manera elegante, y de hecho, se puede y se debe hacer. En otros lenguajes, esto se logra a través de la composición de funciones o el operador de canalización, que, por cierto, se está comenzando a usar gradualmente en el mismo JavaScript: https://github.com/tc39/proposal-pipeline-operator.*
diff --git a/modules/40-define-functions/100-define-function/es/EXERCISE.md b/modules/40-define-functions/100-define-function/es/EXERCISE.md
index 566fc31f..dc0963ee 100644
--- a/modules/40-define-functions/100-define-function/es/EXERCISE.md
+++ b/modules/40-define-functions/100-define-function/es/EXERCISE.md
@@ -1,8 +1,9 @@
-
-Implementa una función llamada `printMotto()` que mostrará en la pantalla la frase *Winter is coming*.
+Un sitio muestra un saludo para cada visitante. Implementa la función `sayHello()`, que muestre en pantalla la frase `Hello, World!`.
```javascript
-printMotto(); // => Winter is coming
+sayHello(); // => Hello, World!
```
-En los ejercicios en los que se requiere implementar una función, no es necesario llamar a esa función. Las pruebas automatizadas se encargarán de llamarla y comprobar su funcionalidad. El ejemplo de llamada anterior se muestra sólo para que entiendas cómo se utilizará tu función.
+En las tareas donde hay que implementar una función, no hace falta llamarla: lo harán las pruebas automatizadas. El ejemplo de llamada se muestra solo para que entiendas cómo se usará la función.
+
+> **Nota:** en el archivo ya hay una línea `export default …`, es de servicio y la necesita el sistema de comprobación; qué es la exportación lo veremos en la lección sobre módulos.
diff --git a/modules/40-define-functions/100-define-function/es/README.md b/modules/40-define-functions/100-define-function/es/README.md
index 9a8ec8f9..6c152f91 100644
--- a/modules/40-define-functions/100-define-function/es/README.md
+++ b/modules/40-define-functions/100-define-function/es/README.md
@@ -1,63 +1,115 @@
+Hasta este momento solo usábamos funciones ya hechas: `console.log()`, `Math.pow()` y otras. Pero en JavaScript se pueden crear funciones propias, y ha llegado el momento de aprender a hacerlo.
-La definición de funciones propias simplifica en gran medida la escritura y el mantenimiento de programas. Las funciones permiten combinar operaciones complejas en una sola. Por ejemplo, enviar un correo electrónico en un sitio web es un proceso bastante complejo que implica interactuar con sistemas externos (Internet). Gracias a la capacidad de definir funciones, toda esta complejidad puede estar oculta detrás de una función simple:
+## Para qué definir funciones
+
+Supongamos que tenemos varios fragmentos de código parecidos:
+
+```javascript
+console.log('Hello, Hexlet!');
+console.log('Hello, world!');
+console.log('Hello, JavaScript!');
+```
+
+Para no repetir la misma plantilla, se la puede envolver en una función propia que reciba un parámetro e imprima la cadena necesaria:
+
+```javascript
+function sayHello(name) {
+ console.log(`Hello, ${name}!`);
+}
+```
+
+Ahora se la puede llamar con distintos argumentos:
```javascript
-// Ejemplo hipotético
-// Lugar de donde se obtiene la función
-import { send } from 'mailer';
+sayHello('Hexlet'); // => Hello, Hexlet!
+sayHello('world'); // => Hello, world!
+sayHello('JavaScript'); // => Hello, JavaScript!
+```
+
+Parece que el código no se ha reducido, pero apareció otra ventaja: si la función se usa en distintos lugares, para cambiar el texto basta con corregir solo su definición. Cuanto más compleja es la tarea y más a menudo aparece, más importante es separar la lógica en funciones aparte.
-const email = 'support@hexlet.io';
-const title = 'Ayuda';
-const body = 'He escrito una historia de éxito, ¿cómo puedo obtener un descuento?';
+## La sintaxis de la definición
+
+```javascript
+function nombreDeLaFuncion(parámetros) {
+ cuerpo
+}
+```
-// Una pequeña llamada - y mucha lógica interna
-send(email, title, body);
+```text
+function greet(name) { ← palabra clave, nombre y parámetro
+ return 'Hello, ' + name; ← cuerpo de la función
+}
```
-Internamente, la realización de una llamada de este tipo tiene bastante lógica. Se conecta al servidor de correo, forma una solicitud correcta basada en el encabezado y el cuerpo del mensaje, y luego lo envía, sin olvidar cerrar la conexión.
+La definición empieza con la palabra clave `function`, después va el nombre de la función (con las mismas reglas que las variables), entre paréntesis la lista de parámetros separados por comas, y el cuerpo de la función se encierra entre llaves `{}`.
+
+## Definir una función no significa llamarla
+
+Definir una función no ejecuta su código. El cuerpo se ejecutará solo al llamarla. Mira el ejemplo:
+
+```javascript
+function sayHi() {
+ console.log('Hi!');
+}
-Creemos nuestra primera función. Su tarea es mostrar un saludo en la pantalla:
+console.log('El programa continúa…');
+```
-```textHello, Hexlet!```
+Aquí la función `sayHi()` está definida, pero su cuerpo no se ejecuta: en la pantalla aparecerá solo `El programa continúa…`. Para que `sayHi()` funcione, hay que llamarla de forma explícita:
```javascript
-// Definición de la función
-// La definición no llama ni ejecuta la función
-// Sólo estamos diciendo que ahora existe esta función
-const showGreeting = () => {
- // Dentro del cuerpo, se indentan 2 espacios para facilitar la lectura
- const text = 'Hello, Hexlet!';
- console.log(text);
+function sayHi() {
+ console.log('Hi!');
}
-// Llamada a la función
-showGreeting(); // => Hello, Hexlet!
+sayHi(); // => Hi!
+console.log('El programa continúa…');
```
-A diferencia de los datos normales, las funciones realizan acciones, por lo que sus nombres casi siempre deben ser verbos: "construir algo", "dibujar algo", "abrir algo".
+## Ejemplo: una función para imprimir la media aritmética
-Todo lo que se describe dentro de las llaves `{}` se llama cuerpo de la función. Dentro del cuerpo se puede escribir cualquier código. Considéralo como un pequeño programa independiente, un conjunto de instrucciones arbitrarias. El cuerpo se ejecuta exactamente en el momento en que se ejecuta la función. Además, cada llamada a la función ejecuta el cuerpo de forma independiente de otras llamadas. Por cierto, el cuerpo puede estar vacío:
+Implementemos una función que **calcula e imprime la media aritmética** de dos números. La media aritmética es la suma de los números dividida por su cantidad. Por ejemplo, la media de 6 y 4: `(6 + 4) / 2 = 5`.
```javascript
-// Definición mínima de una función
-const noop = () => {
- // Aquí podría haber código, pero no lo hay
+function printAverage(a, b) {
+ const total = a + b;
+ const average = total / 2;
+ console.log(average);
}
-noop();
+printAverage(6, 4); // => 5
```
-La definición de una función se parece sospechosamente a la creación de una constante. De hecho, en realidad, la definición de una función consta de dos partes: la definición en sí `() => { }` y la asignación a una constante:
+Aquí `a` y `b` son los parámetros de entrada, `total` contiene su suma, `average` se obtiene dividiendo la suma por 2, y `console.log()` muestra el resultado.
+
+## Nombres y orden de los parámetros
-1. Definición: `() => { }`
-2. Asignación: `const nameOfFunction = ...`
+El nombre de un parámetro puede ser cualquiera; lo importante es que refleje el sentido del valor que llegará dentro. Con el código de fuera no está relacionado de ninguna manera:
-Técnicamente, es posible crear una función que esté simplemente definida, pero que no se pueda utilizar porque no tiene nombre:
+```javascript
+function getLastChar(str) {
+ return str[str.length - 1];
+}
+
+// Dentro de la función str será igual a 'Winter is coming'.
+// El nombre de la variable de fuera no está ligado al nombre del parámetro
+const text = 'Winter is coming';
+console.log(getLastChar(text)); // => g
+```
+
+Cuando hay dos parámetros o más, para la mayoría de las funciones pasa a importar el orden en que se pasan. Si se cambia, la función funcionará de otra manera:
```javascript
-() => {
- // Código funcional, pero inútil
-};
+// El primer parámetro es qué buscamos, el segundo por qué lo cambiamos
+console.log('google'.replace('go', 'mo')); // => moogle
+
+// No se reemplazó nada: dentro de 'google' no hay 'mo'
+console.log('google'.replace('mo', 'go')); // => google
```
-El concepto de "crear una función" tiene muchos sinónimos: "declarar", "definir" e incluso "implementar" (de la palabra implement). Todos ellos se encuentran en la práctica diaria en este trabajo.
+En JavaScript existe también otra forma abreviada de escribir funciones: la forma de flecha. Tiene una lección aparte más adelante en este módulo.
+
+## Reutilización y legibilidad
+
+Las funciones ayudan a evitar la duplicación y hacen los programas más claros. El propio nombre de la función dice qué hace. Esto es especialmente importante en proyectos grandes, donde el código lo leen otros programadores (o tú mismo un mes después).
diff --git a/modules/40-define-functions/150-return/es/README.md b/modules/40-define-functions/150-return/es/README.md
index 8491843c..560a25e5 100644
--- a/modules/40-define-functions/150-return/es/README.md
+++ b/modules/40-define-functions/150-return/es/README.md
@@ -1,114 +1,85 @@
+En esta lección aprenderemos a escribir funciones que **devuelven valores**. Esas funciones entregan el resultado de su trabajo, como si dijeran: «Toma, ya lo calculé».
-Las funciones que definimos en las lecciones anteriores terminaban su ejecución imprimiendo datos en la pantalla:
+Por ejemplo, una función puede devolver una cadena con texto procesado o un número calculado con una fórmula. El valor devuelto se puede usar después: guardarlo en una variable, pasarlo a otra función o mostrarlo en pantalla.
-```javascript
-const greeting = () => {
- console.log('Hello, Hexlet!');
-};
-```
-
-Sin embargo, este tipo de funciones tienen un uso limitado, ya que no se puede utilizar el resultado de su ejecución en el programa. Vamos a ver esto en un ejemplo.
-
-Tomemos la tarea de procesar direcciones de correo electrónico. Cuando un usuario se registra en un sitio web, puede ingresar su correo electrónico de diferentes maneras:
-
-* Añadiendo espacios en blanco al principio o al final `_support@hexlet.io__`
-* Usando letras en diferentes mayúsculas y minúsculas `SUPPORT@hexlet.io`
+Para que una función entregue un resultado se usa la palabra clave especial `return`. Termina la ejecución de la función e indica qué es exactamente lo que hay que devolver.
-Si guardamos la dirección de correo electrónico en esta forma en la base de datos, es probable que el usuario no pueda iniciar sesión en el sitio web, ya que ingresará la dirección sin espacios y con letras en mayúsculas diferentes. Para evitar esto, es necesario preparar la dirección de correo electrónico antes de guardarla en la base de datos. Se debe convertir a minúsculas y eliminar espacios en blanco al principio y al final de la cadena. Esta tarea se puede resolver en un par de líneas de código:
+Aquí tienes una función que pone el texto en mayúsculas:
```javascript
-const saveEmail = () => {
- // En realidad, el correo electrónico proviene de un formulario
- const email = ' SuppORT@hexlet.IO';
- // Eliminamos espacios en blanco al principio y al final
- const trimmedEmail = email.trim();
- const preparedEmail = trimmedEmail.toLowerCase();
- console.log(preparedEmail);
- // Aquí iría la escritura en la base de datos
-};
-```
+function shout(name) {
+ return name.toUpperCase();
+}
-Este código es posible gracias al retorno de valores. Los métodos `trim()` y `toLowerCase()` no imprimen nada en la pantalla (en la consola), sino que **devuelven** el resultado de su ejecución. Por lo tanto, podemos almacenar el resultado en constantes. Si en lugar de esto imprimieran en la pantalla, no podríamos asignar el resultado de su ejecución a una constante, lo cual es lo que ocurre con la función `greeting()` que se mostró anteriormente:
+const result = shout('hexlet');
+console.log(result); // => HEXLET
-```javascript
-const message = greeting();
-console.log(message); // => undefined
+const result2 = shout('code-basics');
+console.log(result2); // => CODE-BASICS
```
-Cambiaremos la función `greeting()` para que en lugar de imprimir el mensaje, retorne el mensaje. Para lograrlo, debemos usar la palabra clave `return` en lugar de imprimir en la pantalla:
+Al llamar `shout('hexlet')` primero se evalúa la expresión `name.toUpperCase()`, que devuelve la cadena `'HEXLET'`. Después `return` entrega ese valor hacia fuera, al lugar desde donde se llamó a la función. En nuestro caso se guarda en la variable `result` y luego se muestra en pantalla.
-```javascript
-const greeting = () => {
- return 'Hello, Hexlet!';
-};
-```
+## La diferencia entre return y console.log
-`return` es una instrucción especial que toma la expresión que se encuentra a la derecha y la devuelve al código que llamó a la función. Tan pronto como JavaScript encuentra la instrucción `return`, la ejecución de la función se detiene.
+A diferencia de `console.log()`, `return` no imprime nada. Simplemente devuelve un valor, y la decisión de qué hacer con él la toma el código que llama.
```javascript
-// Ahora podemos usar el resultado de la función
-const message = greeting();
-console.log(message); // => Hello, Hexlet!
-// Incluso podemos realizar acciones en el resultado
-console.log(message.toUpperCase()); // => HELLO, HEXLET!
+// Esta función imprime, pero no devuelve nada
+function printSum(a, b) {
+ console.log(a + b);
+}
+
+// Esta función devuelve el resultado
+function getSum(a, b) {
+ return a + b;
+}
+
+// El resultado devuelto se puede usar después
+const sum = getSum(3, 4);
+console.log(sum * 2); // => 14
```
-Cualquier código después de la instrucción `return` no se ejecuta:
+## Devolver una expresión evaluada
-```javascript
-const greetingWithCodeAfterReturn = () => {
- return 'Hello, Hexlet!';
- console.log('Nunca me ejecutaré');
-};
-```
-
-Incluso si una función devuelve un valor, eso no limita la posibilidad de imprimir en la pantalla. Además de retornar valores, también podemos imprimir:
+En `return` normalmente se indica una **expresión**, que primero se evalúa y después se pasa el resultado hacia fuera:
```javascript
-const greetingWithReturnAndPrinting = () => {
- console.log('Apareceré en la consola');
- return 'Hello, Hexlet!';
-};
+function fullName(first, last) {
+ return `${first} ${last}`;
+}
-// Esto imprimirá el texto en la pantalla y también devolverá el valor
-const message = greetingWithReturnAndPrinting ();
+const name = fullName('Aria', 'Stark');
+console.log(name); // => Aria Stark
```
-No solo se pueden retornar valores concretos. Dado que `return` funciona con expresiones, casi cualquier cosa puede estar a la derecha de él. Sin embargo, siempre es importante mantener el código legible:
+Primero se evalúa la plantilla de cadena, y ya el valor listo se devuelve hacia fuera.
-```javascript
-const greeting = () => {
- const message = 'Hello, Hexlet!';
- return message;
-};
-```
+## Funciones de varias líneas
-En este ejemplo, no estamos retornando la variable en sí, sino el valor que contiene. A continuación, un ejemplo con cálculos:
+A veces en el cuerpo de la función hay que dar varios pasos antes de obtener el resultado. Entonces se escriben varias líneas, y al final se usa `return`. Por ejemplo, una función que formatea un nombre: quita los espacios de los extremos y pasa las letras a mayúsculas.
```javascript
-const doubleFive = () => {
- // o return 5 + 5
- const result = 5 + 5;
- return result;
-};
+function formatName(name) {
+ const clean = name.trim();
+ const uppercased = clean.toUpperCase();
+ return uppercased;
+}
+
+console.log(formatName(' hexlet ')); // => HEXLET
```
-Pregunta de autocomprobación. ¿Qué devolverá la función `run()`, definida abajo, cuando se le llame?
+## El código después de return
-```javascript
-// Definición
-const run = () => {
- return 5;
- return 10;
-};
-
-// ¿Qué se imprimirá en la pantalla?
-console.log(run());
-```
+Cuando la ejecución llega a `return`, la función termina de inmediato. Todo lo que esté escrito después, dentro de la función, **no se ejecutará**:
-
-Respuesta
+```javascript
+function example() {
+ return 'listo';
+ console.log('este código nunca se ejecutará');
+}
-En la pantalla se imprimirá `5`.
+console.log(example()); // => listo
+```
-
+Por eso `return` se escribe normalmente al final de la lógica. Más adelante, cuando lleguemos a las construcciones condicionales, verás que esos «finales» dentro de una misma función pueden ser varios.
diff --git a/modules/40-define-functions/340-default-parameters/es/EXERCISE.md b/modules/40-define-functions/340-default-parameters/es/EXERCISE.md
index f0fb81eb..1bac4226 100644
--- a/modules/40-define-functions/340-default-parameters/es/EXERCISE.md
+++ b/modules/40-define-functions/340-default-parameters/es/EXERCISE.md
@@ -1,17 +1,8 @@
-
-Implementa la función `getHiddenCard()`, que recibe como entrada el número de una tarjeta de crédito (compuesto por 16 dígitos) como una cadena y devuelve su versión oculta, que se puede utilizar en el sitio web para mostrarla. Si la tarjeta original tenía el número *2034399002125581*, entonces la versión oculta se verá así *\*\*\*\*5581*. En otras palabras, la función reemplaza los primeros 12 caracteres por asteriscos. El número de asteriscos se controla mediante el segundo parámetro opcional. El valor predeterminado es 4.
+Escribe la función `getHiddenCard(cardNumber, starsCount = 4)`, que recibe el número de una tarjeta (una cadena) y devuelve el número oculto: los asteriscos más los últimos 4 dígitos.
```javascript
-// La tarjeta de crédito se pasa como una cadena
-getHiddenCard('1234567812345678', 2); // **5678
-getHiddenCard('1234567812345678', 3); // ***5678
-getHiddenCard('1234567812345678'); // ****5678
-getHiddenCard('2034399002121100', 1); // *1100
+getHiddenCard('1234567890123456') // => '****3456'
+getHiddenCard('1234567890123456', 2) // => '**3456'
```
-Para completar la tarea, necesitarás el método `repeat()` de la cadena, que repite la cadena un número determinado de veces.
-
-```javascript
-'+'.repeat(5); // +++++
-'o'.repeat(3); // ooo
-```
+Usa `'*'.repeat(starsCount)` y `.slice(-4)`.
diff --git a/modules/40-define-functions/340-default-parameters/es/README.md b/modules/40-define-functions/340-default-parameters/es/README.md
index 56057f53..32bffc91 100644
--- a/modules/40-define-functions/340-default-parameters/es/README.md
+++ b/modules/40-define-functions/340-default-parameters/es/README.md
@@ -1,52 +1,75 @@
+Las funciones pueden recibir parámetros. A veces resulta cómodo fijar un valor ya en la definición de la función, para no indicarlo en cada llamada. Ese valor se llama **valor por defecto**.
-En programación, muchas funciones y métodos tienen parámetros que rara vez cambian. En estos casos, se les asignan valores predeterminados que se pueden cambiar según sea necesario. Esto reduce un poco la cantidad de código repetitivo. Por ejemplo:
+Si el argumento no se pasa, se usa ese valor. Si el argumento se indica, reemplaza al valor por defecto.
```javascript
-// Función de potencia
-// El segundo parámetro tiene un valor predeterminado de 2
-const pow = (x, base = 2) => {
- return x ** base;
-};
-// 3 elevado a la segunda potencia (el 2 es el valor predeterminado)
-pow(3); // 9
-// tres elevado a la tercera potencia
-pow(3, 3); // 27
+function greet(name = 'World') {
+ console.log(`Hello, ${name}!`);
+}
+
+greet('Alice'); // => Hello, Alice!
+greet(); // => Hello, World! (se usó el valor por defecto)
```
-El valor predeterminado se ve como una asignación normal en la definición. Solamente se activa si el argumento no se pasa. Hay que acostumbrarse a esto. El valor predeterminado incluso puede estar presente cuando solo hay un parámetro:
+## Ejemplo: repetir un texto
+
+Hagamos una función que repita una cadena varias veces. Que por defecto sea una vez, pero que se pueda indicar otra cantidad si se quiere. Para repetir una cadena, JavaScript tiene el método `repeat()`:
```javascript
-const print = (text = 'nada') => console.log(text);
+function repeat(text, times = 1) {
+ return text.repeat(times);
+}
-print(); // "Nada"
-print("Hexlet"); // Hexlet
+console.log(repeat('Hi')); // => Hi
+console.log(repeat('Hi', 3)); // => HiHiHi
```
-Puede haber cualquier cantidad de parámetros con valores predeterminados:
+```text
+function repeat(text, times = 1) ← times tiene un valor por defecto
-```javascript
-const f = (a = 5, b = 10, c = 100) => { ... }
+repeat('go') → times = 1 (por defecto)
+repeat('go', 5) → times = 5 (indicado de forma explícita)
```
-Los valores predeterminados tienen una peculiaridad: deben ir al final de la lista de parámetros. Los valores pasados a la función siempre se asignan a los parámetros de izquierda a derecha, en el orden en que se pasan. Esto significa que si los valores predeterminados están a la izquierda en la lista de parámetros, antes de los parámetros normales, cuando se llama a la función con argumentos, los valores de los argumentos se colocarán en lugar de los valores predeterminados. Por ejemplo:
+Los parámetros opcionales se indican siempre **al final** de la lista. Por eso primero va el parámetro obligatorio `text`, y solo después `times` con su valor por defecto.
+
+## Ejemplo: unir palabras con un separador
+
+Por defecto las palabras se unen con un espacio, pero se puede indicar otro carácter:
```javascript
-// Llamamos a esta función con los siguientes argumentos: f(1, 2, 3)
-const f = (a = 5, b = 10, c = 100, x) => { ... }
-// los parámetros tendrán los siguientes valores: a = 1, b = 2, c = 3, x = undefined
-// no pasamos nada a x, por lo que JS le asigna el valor undefined
+function joinWords(word1, word2, separator = ' ') {
+ return word1 + separator + word2;
+}
-// Por eso los parámetros con valores predeterminados deben ir a la derecha de los normales,
-// de lo contrario, se sobrescribirán o un parámetro normal puede quedar sin valor
+console.log(joinWords('King', 'Road')); // => King Road
+console.log(joinWords('Dragon', 'stone', '-')); // => Dragon-stone
+```
-// Llamamos a la función, f(1, 2)
-const f = (a = 5, x, b = 10, c = 100) => { ... }
+## Ejemplo: varios parámetros por defecto
-// a = 1, x = 2, los demás parámetros obtienen los valores predeterminados
+Una función puede tener más de un parámetro con valor por defecto. Hagamos una función que construya una línea separadora. Por defecto el carácter es el guion y la longitud es 10:
-// Aquí todo está bien, no hay sorpresas
-const f = (x, a = 5, b = 10, c = 100) => { ... }
+```javascript
+function makeLine(symbol = '-', length = 10) {
+ return symbol.repeat(length);
+}
-// Y aquí también
-const f = (x, y, a = 5, b = 10, c = 100) => { ... }
+console.log(makeLine()); // => ----------
+console.log(makeLine('*')); // => **********
+console.log(makeLine('*', 5)); // => *****
+console.log(makeLine('#', 3)); // => ###
```
+
+## Ejemplo: ocultar el número de una tarjeta
+
+```javascript
+function getHiddenCard(cardNumber, starsCount = 4) {
+ return '*'.repeat(starsCount) + cardNumber.slice(-4);
+}
+
+console.log(getHiddenCard('1234567890123456')); // => ****3456
+console.log(getHiddenCard('1234567890123456', 2)); // => **3456
+```
+
+El parámetro `starsCount` es igual a `4` por defecto, pero se puede pasar otro valor.
diff --git a/modules/40-define-functions/350-type-annotations/es/README.md b/modules/40-define-functions/350-type-annotations/es/README.md
index c9a5ee9d..31f0bf69 100644
--- a/modules/40-define-functions/350-type-annotations/es/README.md
+++ b/modules/40-define-functions/350-type-annotations/es/README.md
@@ -1,9 +1,15 @@
-En JavaScript se puede pasar cualquier valor a una función. A veces esto complica la comprensión del código: no siempre queda claro qué espera la función y qué devuelve. La sintaxis de JavaScript no tiene anotaciones de tipos, pero existe un estándar de facto — **JSDoc**: comentarios especiales antes de la función que entienden los editores y las herramientas de verificación.
+En JavaScript se puede pasar cualquier valor a una función. A veces esto complica la comprensión del código: no siempre queda claro qué espera exactamente la función y qué devuelve. Para que el código sea más claro, los tipos se describen de forma explícita. La sintaxis de JavaScript no tiene anotaciones de tipos, pero existe un estándar de facto: **JSDoc**, comentarios especiales antes de la función que entienden los editores y las herramientas de verificación. Así resolvemos varias cosas a la vez:
-## Cómo anotar los tipos de los parámetros
+- Mejoramos el trabajo del editor de código: obtenemos sugerencias, mejor autocompletado y cosas así.
+- Ayudamos a los agentes de IA a ver más rápido la estructura y tomar decisiones más correctas, minimizando errores accidentales.
+- Aparece la posibilidad de comprobar la corrección del programa sin ejecutarlo, mediante la verificación estática. Esa verificación no garantiza que la lógica del programa esté escrita correctamente, pero al menos no habrá errores de tipos.
-Un comentario JSDoc comienza con `/**` y se coloca justo antes de la definición de la función. El tipo de cada parámetro se declara con la etiqueta `@param`, y el tipo del valor de retorno con `@returns`. El tipo se escribe entre llaves:
+## Cómo indicar los tipos de los parámetros
+
+Un comentario JSDoc empieza con `/**` y se coloca justo antes de la definición de la función. El tipo de cada parámetro se indica con la etiqueta `@param`, y el tipo del valor devuelto con la etiqueta `@returns`. El tipo en sí se escribe entre llaves.
+
+Veámoslo con el ejemplo de una función que calcula la suma de dos valores recibidos:
```javascript
/**
@@ -18,18 +24,84 @@ function add(a, b) {
console.log(add(2, 3)); // => 5
```
-Ahora el editor sabe que `add()` recibe dos números y devuelve un número. Si intentas pasar una cadena, el editor lo marcará como un problema.
+```text
+/**
+ * @param {number} a ← tipo del parámetro a
+ * @param {number} b ← tipo del parámetro b
+ * @returns {number} ← tipo del valor devuelto
+ */
+```
+
+Ahora el editor de código sugerirá que la función `add()` recibe dos números y devuelve un número. Si se intenta pasar una cadena, el editor lo marcará como un problema y avisará:
+
+```javascript
+add('2', 3); // Argument of type 'string' is not assignable to parameter of type 'number'
+```
+
+## Qué tipos se usan en las anotaciones
+
+En esta etapa basta con conocer las anotaciones de los tipos de datos simples, los primitivos:
+
+- `number` para los números: en JavaScript hay un solo tipo numérico, tanto para enteros como para decimales
+- `string` para las cadenas
+- `boolean` para los valores lógicos (`true` o `false`)
+
+```javascript
+/**
+ * @param {string} name
+ * @param {number} age
+ * @param {number} height
+ * @returns {string}
+ */
+function describe(name, age, height) {
+ return `${name}, ${age} años, altura ${height}`;
+}
+
+console.log(describe('Anna', 25, 1.7));
+// => Anna, 25 años, altura 1.7
+```
+
+Si la función no devuelve nada, como tipo devuelto se indica `void`. Por ejemplo, una función puede solo imprimir texto en pantalla:
+
+```javascript
+/**
+ * @param {string} name
+ * @returns {void}
+ */
+function printGreeting(name) {
+ console.log(`Hello, ${name}!`);
+}
+
+printGreeting('Anna');
+// => Hello, Anna!
+```
+
+## Ejemplo con parámetros por defecto
+
+Las anotaciones funcionan igual tanto para los parámetros obligatorios como para los que tienen un valor por defecto. El nombre del parámetro opcional se encierra entre corchetes, y después del signo `=` se indica el valor estándar:
+
+```javascript
+/**
+ * @param {string} name
+ * @param {string} [greeting='Hello']
+ * @returns {string}
+ */
+function greet(name, greeting = 'Hello') {
+ return `${greeting}, ${name}`;
+}
+
+console.log(greet('Anna')); // => Hello, Anna
+console.log(greet('Kirill', 'Hi')); // => Hi, Kirill
+```
-## Qué tipos se usan
+En este ejemplo `name` es un parámetro obligatorio, y `greeting` tiene un valor por defecto. Las anotaciones muestran los tipos de ambos parámetros y del resultado devuelto.
-En esta etapa basta con conocer las anotaciones de los tipos primitivos:
+## Las anotaciones y la verificación del código
-- `number` para números — JavaScript tiene un único tipo numérico para enteros y decimales
-- `string` para cadenas
-- `boolean` para valores lógicos (`true` o `false`)
+JavaScript en sí no comprueba las anotaciones JSDoc durante la ejecución del programa, pero existen herramientas que saben hacerlo sin ejecutar el código. Ese enfoque se llama **verificación estática del código**.
-Si una función no devuelve nada, se usa `void` como tipo de retorno. Para parámetros opcionales con valores por defecto, el nombre del parámetro se encierra entre corchetes: `@param {string} [greeting='Hello']`.
+«Estática» significa que la verificación ocurre antes de ejecutar el programa. La herramienta lee el código fuente y comprueba si los valores pasados corresponden a los tipos indicados. Por ejemplo, si la función recibe una cadena y tú pasas un número, la verificación estática lo mostrará como un error. En el mundo de JavaScript esa verificación la hace el compilador de TypeScript: en un modo especial lee archivos JS normales y entiende los tipos de los comentarios JSDoc.
-## Anotaciones y verificación estática
+Resulta especialmente cómodo cuando el editor resalta esos errores justo mientras se escribe el código. Eso permite ver el problema de inmediato y corregirlo sin esperar a ejecutar el programa. Gracias a ello, muchos errores inesperados se detectan de antemano y en el código en funcionamiento quedan menos.
-JavaScript no verifica las anotaciones JSDoc durante la ejecución, pero hay herramientas que pueden hacerlo sin ejecutar el código — esto se llama **verificación estática**. En el mundo de JavaScript, el compilador de TypeScript puede leer archivos JS y entender los tipos de los comentarios JSDoc. Las anotaciones son opcionales, pero usarlas se considera una buena práctica. Cuando los tipos se vuelven numerosos, los desarrolladores suelen pasar a **TypeScript** — un superconjunto de JavaScript con anotaciones integradas en la sintaxis.
+Las anotaciones no son obligatorias. Las funciones se pueden escribir sin ellas y JavaScript funcionará igual. Pero cuando las anotaciones están, el código se vuelve más claro para las personas y más cómodo para los editores. Anotar las funciones en tu propio código se considera una buena práctica. Y cuando los tipos se vuelven muchos, los desarrolladores a menudo pasan a **TypeScript**, un lenguaje superconjunto de JavaScript donde las anotaciones están integradas directamente en la sintaxis.
diff --git a/modules/50-loops/15-conditions-inside-loops/es/README.md b/modules/50-loops/15-conditions-inside-loops/es/README.md
index a2535cd3..1dc53fba 100644
--- a/modules/50-loops/15-conditions-inside-loops/es/README.md
+++ b/modules/50-loops/15-conditions-inside-loops/es/README.md
@@ -1,18 +1,48 @@
+El cuerpo de un bucle, igual que el cuerpo de una función, es el lugar donde se ejecutan las instrucciones. Eso significa que dentro se puede usar todo lo estudiado antes, por ejemplo las construcciones condicionales. Así el programa repite una misma acción varias veces, pero en cada repetición toma una decisión.
-El cuerpo de un bucle, al igual que el cuerpo de una función, es el lugar donde se ejecutan las instrucciones. Esto significa que podemos utilizar todo lo que hemos aprendido hasta ahora dentro de él, como por ejemplo, estructuras condicionales.
+Supongamos que hay que recorrer los números del `1` al `10` e imprimir solo los pares. El bucle recorre todos los números seguidos, y la condición de dentro decide cuáles llegan a la pantalla:
-Imagina una función que cuenta cuántas veces aparece una letra en una oración. Aquí tienes un ejemplo de cómo funciona:
+```javascript
+let number = 1;
+while (number <= 10) {
+ if (number % 2 === 0) {
+ console.log(number);
+ }
+ number = number + 1;
+}
+
+// => 2
+// => 4
+// => 6
+// => 8
+// => 10
+```
+
+El contador se incrementa después de la comprobación **en cualquier caso**. Eso es importante: si se incrementara `number` solo dentro del `if`, el bucle se detendría en el primer número impar y funcionaría infinitamente.
+
+## Cómo funciona paso a paso
+
+Antes de la primera repetición `number` es igual a `1`.
+
+**Paso 1.** La condición del bucle `number <= 10` es verdadera, el programa entra en el cuerpo. El número `1` es impar, el bloque `if` no se ejecuta. Después `number` se incrementa hasta `2`.
+
+**Paso 2.** La condición vuelve a ser verdadera. El número `2` es par, así que se imprime `2`. Después `number` se incrementa hasta `3`.
+
+Más adelante el bucle comprueba cada número: los impares los omite, los pares los muestra. Cuando `number` llegue a ser igual a `11`, la condición `number <= 10` será falsa y el bucle terminará.
+
+## La condición cambia la acción, no el avance
+
+En esos bucles resulta cómodo separar dos partes: el contador lleva el programa al valor siguiente, y el `if` decide qué hacer con el valor actual.
+
+Veamos una función que cuenta cuántas veces aparece una letra en una oración:
```javascript
countChars('Fear cuts deeper than swords.', 'e'); // 4
-// Si no se encuentra ninguna coincidencia, el resultado es 0
+// Si no se encontró nada, el resultado es 0 coincidencias
countChars('Sansa', 'y'); // 0
```
-Antes de ver el contenido de la función, intenta responder las siguientes preguntas:
-
-* ¿Es esta operación una agregación?
-* ¿Cómo se comprueba si un carácter está presente?
+La implementación:
```javascript
const countChars = (str, char) => {
@@ -31,8 +61,4 @@ const countChars = (str, char) => {
};
```
-Este problema es una operación de agregación. Aunque no cuenta todos los caracteres, aún es necesario analizar cada uno para calcular la suma total.
-
-La diferencia clave de este bucle con los que hemos visto anteriormente es que tiene una condición dentro del cuerpo. La variable `count` solo se incrementa cuando el carácter actual coincide con el esperado.
-
-De lo contrario, esta es una función agregada típica que devuelve la cantidad de caracteres necesarios al código que la llama.
+Esta tarea es de agregación. A pesar de que no cuenta todos los caracteres, para calcular la suma hay que analizar igualmente cada carácter. La diferencia clave con la agregación habitual es la presencia de una condición dentro del cuerpo: la variable `count` se incrementa solo cuando el carácter actual coincide con el esperado. La condición dentro del bucle puede comprobar cualquier cosa: la paridad de un número, la coincidencia de un carácter, la longitud de una cadena. Lo principal es que el contador siga cambiando y que el bucle pueda terminar.
diff --git a/modules/50-loops/30-syntactic-sugar/es/README.md b/modules/50-loops/30-syntactic-sugar/es/README.md
index 993352f3..952115ba 100644
--- a/modules/50-loops/30-syntactic-sugar/es/README.md
+++ b/modules/50-loops/30-syntactic-sugar/es/README.md
@@ -1,10 +1,59 @@
+En programación aparecen a menudo construcciones repetitivas. En JavaScript, igual que en muchos otros lenguajes, existe la posibilidad de abreviar su escritura. Esas simplificaciones se llaman **azúcar sintáctico**: hacen el código más corto y más cómodo, conservando el mismo resultado.
-Las construcciones como `index = index + 1` se utilizan bastante en JavaScript, por lo que los creadores del lenguaje agregaron una forma abreviada: `index += 1`. Estas abreviaciones se conocen como **azúcar sintáctico**, puesto que hacen que el proceso de escribir código sea un poco más fácil y agradable, "endulzándolo" :)
+## Formas abreviadas de asignación
-Existen formas abreviadas para todas las operaciones aritméticas y para la concatenación de cadenas:
+A menudo hace falta cambiar el valor de una variable: sumarle algo, restarle, multiplicarlo o dividirlo. La variante básica se ve así:
-- `a = a + 1` → `a += 1`
-- `a = a - 1` → `a -= 1`
-- `a = a * 2` → `a *= 2`
-- `a = a / 1` → `a /= 1`
-- `a = a + 'foo'` → `a += 'foo'`
+```javascript
+index = index + 1;
+count = count * 2;
+total = total - 5;
+price = price / 3;
+```
+
+JavaScript permite escribirlo más corto, con operadores combinados:
+
+```javascript
+index += 1; // lo mismo que index = index + 1
+count *= 2; // lo mismo que count = count * 2
+total -= 5; // lo mismo que total = total - 5
+price /= 3; // lo mismo que price = price / 3
+```
+
+## Azúcar en los bucles
+
+En los bucles esas abreviaturas aparecen con especial frecuencia: normalmente cambiamos el contador y acumulamos el resultado.
+
+```javascript
+let sum = 0;
+let index = 1;
+
+while (index <= 5) {
+ sum += index; // lo mismo que sum = sum + index
+ index += 1; // lo mismo que index = index + 1
+}
+
+console.log(sum); // => 15
+```
+
+Sin las abreviaturas el cuerpo del bucle sería más largo:
+
+```javascript
+while (index <= 5) {
+ sum = sum + index;
+ index = index + 1;
+}
+```
+
+## Otras operaciones
+
+Esa forma de escribir funciona no solo con números. Para las cadenas se usa el operador de concatenación:
+
+```javascript
+let text = 'Hello';
+text += ' World'; // lo mismo que text = text + ' World'
+```
+
+## Abreviaturas admitidas
+
+La forma abreviada existe para casi todos los operadores: `+=`, `-=`, `*=`, `/=`, `%=`, `**=`. Todos funcionan con el mismo principio: toman el valor actual de la variable, aplican la operación y guardan el resultado en la misma variable.