diff --git a/00_intro.md b/00_intro.md index 1dd4fb6d0..f129bc7e3 100644 --- a/00_intro.md +++ b/00_intro.md @@ -456,8 +456,8 @@ otro entorno en donde programar JavaScript. A lo largo del libro, hay cinco _capítulos de proyectos_, que describen programas de ejemplo más grandes para darte una idea de la programación real. En orden de aparición, trabajaremos en la construcción de un -[robot de delivery](robot), un [lenguaje de programación](lenguaje), -un [juego de plataforma](juego), un [programa de paint](paint) y un [sitio web dinámico](skillsharing). +[robot de entrega](robot), un [lenguaje de programación](lenguaje), +un [juego de plataforma](juego), un [programa de pintura](paint) y un [sitio web dinámico](skillsharing). La parte del lenguaje del libro comienza con cuatro capítulos para presentar la estructura básica del lenguaje de JavaScript. Estos introducen diff --git a/01_values.md b/01_values.md index f1fe11f7b..bec164908 100644 --- a/01_values.md +++ b/01_values.md @@ -51,7 +51,7 @@ Entonces ese es el número binario 00001101, o 8 + 4 + 1, o 13. {{index memory, "volatile data storage", "hard drive"}} -Imagina un mar de bits—un océano de ellos. Una computadora moderna +Imagina un mar de bits, un océano repleto. Una computadora moderna promedio tiene mas de 30 billones de bits en su almacenamiento de datos volátiles (memoria funcional). El almacenamiento no volátil (disco duro o equivalente) tiende a tener unas cuantas mas ordenes de magnitud. @@ -93,18 +93,18 @@ En un programa hecho en JavaScript, se escriben de la siguiente manera: {{index "binary number"}} -Utiliza eso en un programa, y ocasionara que el patron de bits +Utiliza eso en un programa, y ocasionará que el patrón de bits que representa el número 13 sea creado dentro de la memoria de la computadora. -{{index [number, representation], bit}} +{{index [number, representación], bit}} -JavaScript utiliza un número fijo de bits, específicamente 64 de ellos, +JavaScript utiliza un número fijo de bits, específicamente 64, para almacenar un solo valor numérico. Solo existen una cantidad finita de patrones que podemos crear con 64 bits, lo que significa que la cantidad de números diferentes que pueden ser representados es limitada. Para una cantidad de _N_ dígitos decimales, la cantidad de números que pueden ser representados es 10^N^. Del mismo modo, dados 64 dígitos binarios, podemos -representar 2^64^ números diferentes, lo que es alrededor de 18 mil trillones +representar 2^64^ números diferentes, lo que es alrededor de 18 trillones (un 18 con 18 ceros más). Eso es muchísimo. La memoria de un computador solía ser mucho mas pequeña que en la actualidad, @@ -118,14 +118,13 @@ con números verdaderamente astronómicos. {{index sign, "floating-point number", "fractional number", "sign bit"}} -A pesar de esto, no todos los números enteros por debajo de 18 mil +A pesar de esto, no todos los números enteros por debajo de 18 trillones caben en un número de JavaScript. Esos bits también almacenan números negativos, por lo que un bit indica el signo de un número. Un problema mayor es que los números no enteros tienen que ser representados también. Para hacer esto, algunos de los bits son usados para almacenar la posición del punto decimal. El número entero mas grande que puede ser -almacenado está en el rango de los 9 trillones (15 ceros)—lo cual es -todavía placenteramente inmenso. +almacenado está en el rango de los nueve mil billones (15 ceros), que sigue siendo inmenso. {{index [number, notation]}} @@ -150,8 +149,8 @@ Eso es 2.998 × 10^8^ = 299,800,000. {{index pi, [number, "precision of"], "floating-point number"}} Los cálculos con números enteros (también llamados _((integer))s_) -mas pequeños a los 9 trillones anteriormente mencionados están -garantizados a ser siempre precisos. Desafortunadamente, los calculos +mas pequeños a los nueve mil billones anteriormente mencionados están +garantizados a ser siempre precisos. Desafortunadamente, los cálculos con números fraccionarios, generalmente no lo son. Así como π (pi) no puede ser precisamente expresado por un número finito de números decimales, muchos números pierden algo de precisión cuando solo hay 64 bits disponibles @@ -202,17 +201,17 @@ El operador `/` tiene la misma precedencia que `*`. Lo mismo aplica para del otro, como en `1 - 2 + 1`, estos se aplican de izquierda a derecha: `(1 - 2) + 1`. -Estas reglas de precedencia no son algo de lo que deberias preocuparte. +Estas reglas de precedencia no son algo de lo que deberías preocuparte. Cuando tengas dudas, solo agrega un paréntesis. -{{index "modulo operator", division, "remainder operator", "% operator"}} +{{index "operador módulo", división, "operador de sobrante", "operador %"}} Existe otro operador aritmético que quizás no reconozcas inmediatamente. El símbolo `%` es utilizado para representar la operación de _residuo_. `X % Y` es el residuo de dividir `X` entre `Y`. Por ejemplo, `314 % 100` produce `14`, y `144 % 12` produce `0`. La precedencia del residuo es la la misma que la de la multiplicación y la división. Frecuentemente veras -que este operador es tambien conocido como _modulo_. +que este operador es también conocido como _modulo_. ### Números especiales @@ -245,8 +244,8 @@ significante. {{index syntax, text, character, [string, notation], "single-quote character", "double-quote character", "quotation mark", backtick}} -El próximo tipo de dato básico es el _((string))_. Los Strings -son usados para representar texto. Son escritos encerrando su contenido +El próximo tipo de dato básico es el _((string))_. Las cadenas (_strings_) +son usados para representar texto. Son escritas encerrando su contenido en comillas: ``` @@ -264,7 +263,7 @@ y al final coincidan. Casi todo puede ser colocado entre comillas, y JavaScript construirá un valor string a partir de ello. Pero algunos caracteres son mas difíciles. Te puedes imaginar que colocar comillas entre comillas podría ser difícil. -Los _Newlines_ (los caracteres que obtienes cuando presionas la tecla de Enter) +Los _saltos de línea_ (los caracteres que obtienes cuando presionas la tecla de Enter) solo pueden ser incluidos cuando el string está encapsulado con comillas invertidas (`` ` ``). @@ -307,8 +306,8 @@ Un carácter de salto de linea es escrito así: \"\\n\"." {{index [string, representation], Unicode, character}} -También los strings deben de ser modelados como una serie de bits para poder -existir dentro del computador. La forma en la que JavaScript hace esto +Las cadenas deben de ser modeladas como una serie de bits para poder +existir dentro de la computadora. La forma en la que JavaScript hace esto es basada en el estándar _((Unicode))_. Este estándar asigna un número a todo carácter que alguna vez pudieras necesitar, incluyendo caracteres en Griego, Árabe, Japones, Armenio, y asi sucesivamente. Si tenemos un número para @@ -327,9 +326,9 @@ tema en el [Capitulo 5](orden_superior#unidades_de_codigo). {{index "+ operator", concatenation}} -Los strings no pueden ser divididos, multiplicados, o substraidos, pero -el operador `+` _puede_ ser utilizado en ellos. No los agrega, sino que -los _concatena_—pega dos strings juntos. La siguiente línea producirá +Los strings no pueden ser divididas, multiplicados o restados, pero +el operador `+` _puede_ ser utilizado en ellos. No los suma, sino que +los _concatena_: pega dos cadenas una tras otra. La siguiente línea producirá el string `"concatenar"`: ``` @@ -343,10 +342,10 @@ a estas en el [Capítulo 4](datos#metodos). {{index interpolation, backtick}} Los strings escritos con comillas simples o dobles se comportan -casi de la misma manera—La unica diferencia es el tipo de comilla que necesitamos +casi de la misma manera—La única diferencia es el tipo de comilla que necesitamos para escapar dentro de ellos. Los strings de comillas inversas, usualmente llamados _((plantillas literales))_, pueden realizar algunos trucos -más. Mas alla de permitir saltos de lineas, pueden también incrustar otros +más. Mas allá de permitir salto de línea, pueden también incrustar otros valores. ``` @@ -361,7 +360,7 @@ posición. El ejemplo anterior produce "_la mitad de 100 es 50_". {{index operator, "typeof operator", type}} -No todo los operadores son simbolos. Algunos se escriben como palabras. +No todo los operadores son símbolos. Algunos se escriben como palabras. Un ejemplo es el operador `typeof`, que produce un string con el nombre del tipo de valor que le demos. @@ -404,7 +403,7 @@ true (verdadero) y false (falso) que se escriben de la misma forma. ### Comparación -{{index comparison}} +{{index comparación}} Aquí se muestra una forma de producir valores Booleanos: @@ -415,7 +414,7 @@ console.log(3 < 2) // → false ``` -{{index [comparison, "of numbers"], "> operator", "< operator", "greater than", "less than"}} +{{index [comparación, "de números"], "> operador", "< operator", "greater than", "less than"}} Los signos `>` y `<` son tradicionalmente símbolos para "mayor que" y "menor que", respectivamente. Ambos son operadores binarios. @@ -439,7 +438,7 @@ incluidos en el ordenamiento. Cuando comparamos strings, JavaScript evalúa los caracteres de izquierda a derecha, comparando los códigos ((Unicode)) uno por uno. -{{index equality, ">= operator", "<= operator", "== operator", "!= operator"}} +{{index igualdad, "operador >=", "operador <=", "operador ==", "operador !="}} Otros operadores similares son `>=` (mayor o igual que), `<=` (menor o igual que), `==` (igual a), y `!=` (no igual a). diff --git a/02_program_structure.md b/02_program_structure.md index 6210df4ef..bf5c12156 100644 --- a/02_program_structure.md +++ b/02_program_structure.md @@ -4,14 +4,14 @@ Y mi corazón brilla de un color rojo brillante bajo mi piel transparente y translúcida, y tienen que administrarme 10cc de JavaScript para conseguir que -regrese. (respondo bien a las toxinas en la sangre.) Hombre, esa cosa es -increible! +regrese. (respondo bien a las toxinas en la sangre.) ¡Hombre, esa cosa es +increíble! quote}} {{index why, "Poignant Guide"}} -{{figure {url: "img/chapter_picture_2.jpg", alt: "Foto de tentaculos sosteniendo objetos", chapter: framed}}} +{{figure {url: "img/chapter_picture_2.jpg", alt: "Foto de tentáculos sosteniendo objetos", chapter: framed}}} En este capítulo, comenzaremos a hacer cosas que realmente se pueden llamar _programación_. Expandiremos nuestro dominio del lenguaje JavaScript @@ -64,8 +64,8 @@ ella. Esto es un programa: Sin embargo, es un programa inútil. Una ((expresión)) puede estar feliz solo con producir un valor, que luego pueda ser utilizado por el código circundante. Una ((declaración)) es independiente por si misma, por lo que equivale a -algo solo si afecta al mundo. Podría mostrar algo en la pantalla—eso -cuenta como cambiar el mundo—o podría cambiar el estado interno de +algo solo si afecta al mundo. Podría mostrar algo en la pantalla, eso +cuenta como cambiar el mundo, o podría cambiar el estado interno de la máquina en una manera que afectará a las declaraciones que vengan después de ella. Estos cambios se llaman _((efecto secundario))s_. Las declaraciones en el ejemplo anterior solo producen los valores `1` y `true` y luego @@ -138,7 +138,7 @@ console.log(humor); {{index [binding, "model of"], "tentacle (analogy)"}} Deberías imaginar a las vinculaciones como tentáculos, en lugar de cajas. -Ellas no _contienen_ valores; ellas los _agarran_—dos vinculaciones pueden +Ellas no _contienen_ valores; ellas los _agarran_, dos vinculaciones pueden referirse al mismo valor. Un programa solo puede acceder a los valores que todavía pueda referenciar. Cuando necesitas recordar algo, creces un tentáculo para aferrarte a él o vuelves a conectar uno de tus tentáculos @@ -202,8 +202,8 @@ fácilmente puedas consultarlo más adelante. {{index "underscore character", "dollar sign", [binding, naming]}} Los nombres de las vinculaciones pueden ser cualquier palabra. Los dígitos pueden -ser parte de los nombres de las vinculaciones pueden—`catch22` es un nombre -válido, por ejemplo—pero el nombre no debe comenzar con un dígito. +ser parte de los nombres de las vinculaciones pueden, `catch22` es un nombre +válido, por ejemplo, pero el nombre no debe comenzar con un dígito. El nombre de una vinculación puede incluir signos de dólar (`$`) o caracteres de subrayado (`_`), pero no otros signos de puntuación o caracteres especiales. @@ -262,7 +262,7 @@ prompt("Introducir contraseña"); {{index parameter, [function, application]}} -Ejecutar una función tambien se conoce como _invocarla_, _llamarla_, o +Ejecutar una función también se conoce como _invocarla_, _llamarla_, o _aplicarla_. Puedes llamar a una función poniendo ((paréntesis)) después de una expresión que produzca un valor de función. Usualmente usarás directamente el nombre de la vinculación que contenga la función. Los valores entre @@ -592,7 +592,7 @@ el ciclo continúa dando vueltas hasta que proporciones un nombre no-vacío. {{index "code structure", whitespace, "programming style"}} En los ejemplos, he estado agregando espacios adelante de declaraciones que -son parte de una declaración más grande. Estos no son necesarios—la computadora +son parte de una declaración más grande. Estos no son necesarios, la computadora aceptará el programa normalmente sin ellos. De hecho, incluso las nuevas ((líneas)) en los programas son opcionales. Podrías escribir un programa en una sola línea inmensa si asi quisieras. @@ -602,7 +602,7 @@ la estructura del código se destaque. En código donde se abren nuevos bloques dentro de otros bloques, puede ser difícil ver dónde termina un bloque y donde comienza el otro. Con la indentación apropiada, la forma visual de un programa corresponde a la forma de los bloques dentro de él. Me gusta -usar dos espacios para cada bloque abierto, pero los gustos varían—algunas +usar dos espacios para cada bloque abierto, pero los gustos varían, algunas personas usan cuatro espacios, y algunas personas usan ((carácteres de tabulación)). Lo cosa importante es que cada bloque nuevo agregue la misma cantidad de espacio. @@ -779,7 +779,7 @@ else accionPorDefault(); Existe un constructo llamado `switch` que está destinada a expresar tales "despachos" de una manera más directa. Desafortunadamente, la sintaxis que JavaScript usa para esto (que heredó de la línea lenguajes de programación -C/Java) es algo incómoda—una cadena de declaraciones `if` podria llegar a verse +C/Java) es algo incómoda, una cadena de declaraciones `if` podria llegar a verse mejor. Aquí hay un ejemplo: ``` @@ -807,7 +807,7 @@ encuentra ningún valor que coincida. Continuará ejecutándose, incluso a través de otras etiquetas, hasta que llegue a una declaración `break`. En algunos casos, como en el caso `"soleado"` del ejemplo, esto se puede usar para compartir algo de código entre casos (recomienda salir para ambos -climas soleado y nublado). Pero ten cuidado—es fácil olvidarse de +climas soleado y nublado). Pero ten cuidado, es fácil olvidarse de `break`, lo que hará que el programa ejecute código que no quieres que sea ejecutado. diff --git a/03_functions.md b/03_functions.md index a9812775e..2dc4fecf9 100644 --- a/03_functions.md +++ b/03_functions.md @@ -96,7 +96,7 @@ Cuando el control se encuentre con tal declaración, inmediatamente salta de la función actual y devuelve el valor retornado al código que llamó la función. Una declaración `return` sin una expresión después de ella hace que la función retorne `undefined`. Funciones que no tienen una -declaración `return` en absoluto, como `hacerSonido`, similarmente retornan +declaración `return` en absoluto, como `hacerSonido`, de manera similar retornan `undefined`. {{index parameter, [function, application], [binding, "from parameter"]}} @@ -110,10 +110,10 @@ el código en la función en sí. {{indexsee "top-level scope", "global scope"}} {{index "var keyword", "global scope", [binding, global], [binding, "scope of"]}} -Cada ((vinculación)) tiene un _((alcace))_, que correspone a la parte del +Cada ((vinculación)) tiene un _((alcace))_, que corresponde a la parte del programa en donde la vinculación es visible. Para vinculaciones definidas fuera de cualquier función o bloque, el alcance es todo el -programa—puedes referir a estas vinculaciones en donde sea que quieras. +programa, puedes referir a estas vinculaciones en donde sea que quieras. Estas son llamadas _globales_. {{index "local scope", [binding, local]}} @@ -122,19 +122,19 @@ Pero las vinculaciones creadas como ((parámetro))s de función o declaradas dentro de una función solo puede ser referenciadas en esa función. Estas se llaman _locales_. Cada vez que se llame a la función, se crean nuevas instancias de estas vinculaciones. Esto proporciona cierto -aislamiento entre funciones—cada llamada de función actúa sobre su pequeño +aislamiento entre funciones, cada llamada de función actúa sobre su pequeño propio mundo (su entorno local), y a menudo puede ser entendida sin saber mucho acerca de lo qué está pasando en el entorno global. {{index "let keyword", "const keyword", "var keyword"}} Vinculaciones declaradas con `let` y `const` son, de hecho, locales al -_((bloque))_ donde esten declarados, así que si creas uno de esas +_((bloque))_ donde estén declarados, así que si creas uno de esas dentro de un ciclo, el código antes y después del ciclo no puede "verlas". En JavaScript anterior a 2015, solo las funciones creaban nuevos alcances, por lo que las vinculaciones de estilo-antiguo, creadas con la palabra clave `var`, son visibles a lo largo de toda la función en la que -aparecen—o en todo el alcance global, si no están dentro de una función. +aparecen, o en todo el alcance global, si no están dentro de una función. ``` let x = 10; @@ -153,7 +153,7 @@ console.log(x + z); Cada ((alcance)) puede "mirar afuera" hacia al alcance que lo rodee, por lo que `x` es visible dentro del bloque en el ejemplo. La excepción es cuando -vinculaciones múltiples tienen el mismo nombre—en ese caso, el código solo +vinculaciones múltiples tienen el mismo nombre, en ese caso, el código solo puede ver a la vinculación más interna. Por ejemplo, cuando el código dentro de la función `dividirEnDos` se refiera a `numero`, estara viendo su _propio_ `numero`, no el `numero` en el alcance global. @@ -182,8 +182,8 @@ funciones, produciendo múltiples grados de localidad. {{index "landscape example"}} -Por ejemplo, esta función—que muestra los ingredientes necesarios para -hacer un lote de humus—tiene otra función dentro de ella: +Por ejemplo, esta función, que muestra los ingredientes necesarios para +hacer un lote de humus, tiene otra función dentro de ella: ``` const humus = function(factor) { @@ -212,7 +212,7 @@ de la función externa. Pero sus vinculaciones locales, como `unidad` o En resumen, cada alcance local puede ver también todos los alcances locales que lo contengan. El conjunto de vinculaciones visibles dentro de un bloque está determinado por el lugar de ese bloque en el texto del programa. -Cada alcance local puede tambien ver todos los alcances locales que lo +Cada alcance local puede también ver todos los alcances locales que lo contengan, y todos los alcances pueden ver el alcance global. Este enfoque para la visibilidad de vinculaciones es llamado _((alcance léxico))_. @@ -228,7 +228,7 @@ y nunca cambia. Esto hace que sea fácil confundir la función con su nombre. {{index [binding, assignment]}} Pero los dos son diferentes. Un valor de función puede hacer todas las cosas que -otros valores pueden hacer—puedes usarlo en ((expresion))es arbitrarias, no +otros valores pueden hacer, puedes usarlo en ((expresion))es arbitrarias, no solo llamarlo. Es posible almacenar un valor de función en una nueva vinculación, pasarla como argumento a una función, y así sucesivamente. Del mismo modo, una vinculación que contenga una función sigue siendo solo @@ -443,7 +443,7 @@ que puedes pasar a una función. Si pasa demasiados, los adicionales son ignorados. Si pasas muy pocos, a los parámetros faltantes se les asigna el valor `undefined`. -La desventaja de esto es que es posible—incluso probable—que +La desventaja de esto es que es posible, incluso probable, que accidentalmente pases la cantidad incorrecta de argumentos a las funciones. Y nadie te dira nada acerca de eso. @@ -497,7 +497,7 @@ En el [próximo capítulo](datos#parametros_rest), veremos una forma en el que el cuerpo de una función puede obtener una lista de todos los argumentos que son pasados. Esto es útil porque hace posible que una función acepte cualquier cantidad de argumentos. Por ejemplo, `console.log` hace -esto—muetra en la consola todos los valores que se le den. +esto, muetra en la consola todos los valores que se le den. ``` console.log("C", "O", 2); @@ -532,14 +532,14 @@ console.log(envolver2()); // → 2 ``` -Esto está permitido y funciona como es de esperar—ambas instancias de +Esto está permitido y funciona como es de esperar, ambas instancias de las vinculaciones todavía pueden ser accedidas. Esta situación es una buena demostración del hecho de que las vinculaciones locales se crean de nuevo para cada llamada, y que las diferentes llamadas no pueden pisotear las distintas vinculaciones locales entre sí. -Esta característica—poder hacer referencia a una instancia específica -de una vinculación local en un alcance encerrado—se llama _((cierre))_. +Esta característica, poder hacer referencia a una instancia específica +de una vinculación local en un alcance encerrado, se llama _((cierre))_. Una función que que hace referencia a vinculaciones de alcances locales alrededor de ella es llamada _un_ cierre. Este comportamiento no solo te libera de tener que preocuparte @@ -640,10 +640,10 @@ paralizante. {{index "premature optimization"}} Por lo tanto, siempre comienza escribiendo algo que sea correcto y fácil de -comprender. Si te preocupa que sea demasiado lento—lo que generalmente +comprender. Si te preocupa que sea demasiado lento, lo que generalmente no sucede, ya que la mayoría del código simplemente no se ejecuta con la suficiente frecuencia como para tomar cantidades significativas de -tiempo—puedes medir luego y mejorar si es necesario. +tiempo, puedes medir luego y mejorar si es necesario. {{index "branching recursion"}} @@ -743,7 +743,7 @@ aún más para explorar _cada_ solución continuada que produzca un número meno o igual a el número objetivo. Como no encuentra uno que llegue al objetivo, retorna `null` a la primera llamada. Ahí el operador `||` genera la llamada que explora `(1 * 3)` para que esta suceda. Esta búsqueda tiene más -suerte—su primera llamada recursiva, a través de _otra_ llamada recursiva, +suerte, su primera llamada recursiva, a través de _otra_ llamada recursiva, encuentra al número objetivo. Esa llamada más interna retorna un string, y cada uno de los operadores `||` en las llamadas intermedias pasa ese string a lo largo, en última instancia retornando la solución. @@ -787,7 +787,7 @@ siempre tengan tres dígitos de largo. 011 Pollos ``` -Esto pide una función de dos argumentos—el numero de vacas y el numero +Esto pide una función de dos argumentos, el numero de vacas y el numero de pollos. Vamos a programar. ``` @@ -844,8 +844,8 @@ imprimirInventarioGranja(7, 11, 3); {{index [function, naming]}} Funciona! Pero ese nombre, `imprimirEtiquetaAlcochadaConCeros`, es un poco -incómodo. Combina tres cosas—impresión, alcochar con ceros y añadir -una etiqueta—en una sola función. +incómodo. Combina tres cosas, impresión, alcochar con ceros y añadir +una etiqueta, en una sola función. {{index "zeroPad function"}} @@ -890,7 +890,7 @@ relleno con diferentes caracteres, y así sucesivamente. Un principio útil es no agregar mucho ingenio a menos que estes absolutamente seguro de que lo vas a necesitar. Puede ser tentador escribir "((framework))s" generalizados para cada funcionalidad que encuentres. -Resiste ese impulso. No realizarás ningún trabajo real de esta manera—solo +Resiste ese impulso. No realizarás ningún trabajo real de esta manera, solo estarás escribiendo código que nunca usarás. {{id pure}} @@ -917,7 +917,7 @@ secundarios. Una función _pura_ es un tipo específico de función de producción-de-valores que no solo no tiene efectos secundarios pero que tampoco depende de los -efectos secundarios de otro código—por ejemplo, no lee vinculaciones globales +efectos secundarios de otro código, por ejemplo, no lee vinculaciones globales cuyos valores puedan cambiar. Una función pura tiene la propiedad agradable de que cuando se le llama con los mismos argumentos, siempre produce el mismo valor (y no hace nada más). Una llamada a tal función puede ser @@ -964,7 +964,7 @@ Un aspecto clave en para comprender a las funciones es comprender los alcances. bloque crea un nuevo alcance. Los parámetros y vinculaciones declaradas en un determinado alcance son locales y no son visibles desde el exterior. Vinculaciones declaradas con `var` se comportan de manera -diferente—terminan en el alcance de la función más cercana o en el alcance global. +diferente, terminan en el alcance de la función más cercana o en el alcance global. Separar las tareas que realiza tu programa en diferentes funciones es util. No tendrás que repetirte tanto, y las funciones pueden diff --git a/05_higher_order.md b/05_higher_order.md index 014e73c8f..df3f68a03 100644 --- a/05_higher_order.md +++ b/05_higher_order.md @@ -203,7 +203,7 @@ tipo de ciclo, y luego provee un cuerpo. Sin embargo, el cuerpo ahora está escr como un valor de función, que está envuelto en el ((paréntesis)) de la llamada a `repetir`. Por eso es que tiene que cerrarse con el corchete de cierre _y_ paréntesis de cierre. En casos como este ejemplo, donde el -cuerpo es una expresión pequeña y única, podrias tambien omitir las +cuerpo es una expresión pequeña y única, podrias también omitir las llaves y escribir el ciclo en una sola línea. ## Funciones de orden superior diff --git a/07_robot.md b/07_robot.md index add4695ec..d3a707ab9 100644 --- a/07_robot.md +++ b/07_robot.md @@ -162,7 +162,7 @@ si no, retorna el estado anterior, ya que este no es un movimiento válido. Luego crea un nuevo estado con el destino como el nuevo lugar del robot. Pero también necesita crear un nuevo conjunto de paquetes—los paquetes que el robot esta llevando (que están en el lugar actual del robot) necesitan de -moverse tambien al nuevo lugar. Y paquetes que están dirigidos al nuevo +moverse también al nuevo lugar. Y paquetes que están dirigidos al nuevo lugar donde deben de ser entregados—es decir, deben de eliminarse del conjunto de paquetes no entregados. La llamada a `map` se encarga de mover los paquetes, y la llamada a `filter` hace la entrega. diff --git a/09_regexp.md b/09_regexp.md index a6dd4981a..0cd045d0f 100644 --- a/09_regexp.md +++ b/09_regexp.md @@ -1427,7 +1427,7 @@ delante del ((exponente)), se puede hacer con `[+\-]?` o `(\+|-|)` {{index "pipe character"}} La parte más complicada del ejercicio es el problema hacer coincidir -ambos `"5."` y `".5"` sin tambien coincidir coincidir con `"."`. Para esto, +ambos `"5."` y `".5"` sin también coincidir coincidir con `"."`. Para esto, una buena solución es usar el operador `|` para separar los dos casos—ya sea uno o más dígitos seguidos opcionalmente por un punto y cero o más dígitos _o_ un punto seguido de uno o más dígitos. diff --git a/11_async.md b/11_async.md index 2302a12c1..7d028beb7 100644 --- a/11_async.md +++ b/11_async.md @@ -466,7 +466,7 @@ por vencida. {{index "Promise class", "callback function", interface}} -Y, como hemos establecido que las promesas son algo bueno, tambien haremos +Y, como hemos establecido que las promesas son algo bueno, también haremos que nuestra función de solicitud retorne una promesa. En términos de lo que pueden expresar, las devoluciones de llamada y las promesas son equivalentes. Las funciones basadas en devoluciones de llamadas se pueden diff --git a/12_language.md b/12_language.md index e09488cb5..80d0ae3e6 100644 --- a/12_language.md +++ b/12_language.md @@ -196,7 +196,7 @@ JavaScript no válido. {{index "parseApply function"}} -Luego cortamos la parte que coincidio del string del programa y +Luego cortamos la parte que coincidió del string del programa y pasamos eso, junto con el objeto para la expresión, a `aplicarAnalisis`, el cual verifica si la expresión es una aplicación. Si es así, analiza una lista de los argumentos entre paréntesis. @@ -268,20 +268,19 @@ console.log(analizar("+(a, 10)")); {{index "error message"}} -Funciona! No nos da información muy útil cuando falla +¡Funciona! No nos da información muy útil cuando falla y no almacena la línea y la columna en que comienza cada expresión, lo que podría ser útil al informar errores más tarde, pero es lo suficientemente bueno para nuestros propósitos. -## The evaluator +## El evaluador -{{index "evaluate function", evaluation, interpretation, "syntax tree", "Egg language"}} +{{index "evaluar función", evaluación, interpretación, "árbol sintáctico", "lenguaje de Egg"}} -What can we do with the syntax tree for a program? Run it, of course! -And that is what the evaluator does. You give it a syntax tree and a -scope object that associates names with values, and it will evaluate -the expression that the tree represents and return the value that this -produces. +¿Qué poddemos hacer son el árrbol sintáctico de un programa? ¡Correrlo, por supuesto! +Y eso es lo que el evaluador hace. Le das un árbol sintáctico y un objeto de ámbito +que asocie nombres con valores, y evaluará la expresión que el árbol representa y regresará +el valor que el árbol produce. ```{includeCode: true} const specialForms = Object.create(null); @@ -313,52 +312,53 @@ function evaluate(expresion, scope) { } ``` -{{index "literal expression", scope}} +{{index "expresión literal", ámbito}} -The evaluator has code for each of the ((expression)) types. A literal -value expression produces its value. (For example, the expression -`100` just evaluates to the number 100.) For a binding, we must check -whether it is actually defined in the scope and, if it is, fetch the -binding's value. +El evaluador tiene código para cada uno de los tipos de ((exprresión)). Un +expresión literal de un valor produce este valor. (Por ejemplo, la expresión `100` evalúa +al número 100.) Para un vínculo de valor, debemos verificar si está definido en el ámbito, +y si lo está, traer el valor vinculado. -{{index [function, application]}} +{{index [función, aplicación]}} -Applications are more involved. If they are a ((special form)), like -`if`, we do not evaluate anything and pass the argument expressions, -along with the scope, to the function that handles this form. If it is -a normal call, we evaluate the operator, verify that it is a function, -and call it with the evaluated arguments. +La apliación implica más cosas. Si son una ((forma especial)), como +`if`, no evaluamos nada y pasamos las expresiones argumento, junto con el +ámbito, a la función que maneja esta forma. Si es una llamada normal, evaluamos el operador, +verificamos que sea una función, y la llamamos con los argumentos evaluados. -We use plain JavaScript function values to represent Egg's function -values. We will come back to this [later](language#egg_fun), when the -special form called `fun` is defined. +Usamos valores función planos de JavaScript para representar los valores función de Egg. +Regresaremos a esto [más tardde](language#egg_fun), cuando forma especial llamada +`fun` está definida. -{{index readability, "evaluate function", recursion, parsing}} -The recursive structure of `evaluate` resembles the similar structure -of the parser, and both mirror the structure of the language itself. -It would also be possible to integrate the parser with the evaluator -and evaluate during parsing, but splitting them up this way makes the -program clearer. +{{index legibilidad, "evaluar función", recursión, parseo}} -{{index "Egg language", interpretation}} +La estructura recursiva de `evaluate` se parece a la estructura del parser, y +ambos reflejan la estructura del lenguaje mismo. También sería posible +integrar el parser con el evaluador y evaluar durante el parseo, +pero separarlos de esta manera hace el programa más claro. -This is really all that is needed to interpret Egg. It is that simple. -But without defining a few special forms and adding some useful values -to the ((environment)), you can't do much with this language yet. -## Special forms +{{index "lenguaje Egg", interpretación}} -{{index "special form", "specialForms object"}} +Esto es todo lo que se necesita para interpretar Egg. Es así de simple. +Pero si no definimos unas cuantas formas especiales y agregamos algunos +valores útiles para el ((entorno)), todavía no podemos hacer mucho con +el lenguaje. + +## Formas especiales + +{{index "formas especiales", "objeto specialForms"}} + +El objeto `specialForms` es usado para definir una sintaxis especial en +Egg. Asocia palabras con funciones que evalúan estas formas. Ahora mismo está +vacío. Agreguemos `if`. -The `specialForms` object is used to define special syntax in Egg. It -associates words with functions that evaluate such forms. It is -currently empty. Let's add `if`. ```{includeCode: true} -specialForms.si = (args, scope) => { +specialForms.if = (args, scope) => { if (args.length != 3) { - throw new SyntaxError("Wrong number of args to si"); + throw new SyntaxError("Wrong number of args to if"); } else if (evaluate(args[0], scope) !== false) { return evaluate(args[1], scope); } else { @@ -367,30 +367,30 @@ specialForms.si = (args, scope) => { }; ``` -{{index "conditional execution", "ternary operator", "?: operator", "conditional operator"}} +{{index "ejecución condicional", "operador ternario", "operador ?:", "operador condicional"}} + +El constructo `if` de Egg espera exactamente tres arrgumentos. Evaluará el primero, +y si el resultado no es `false`, evaluará el segundo. En otro caso, el +tercero será evaluado. Esta forma `if` es más parecidda al operaddor +ternario `?:` que al `if` if de JavaScript. Es una expresión, no una +sentencia, y produce un valor: el resultado del segundo o tercer argumento. -Egg's `si` construct expects exactly three arguments. It will evaluate -the first, and if the result isn't the value `false`, it will evaluate -the second. Otherwise, the third gets evaluated. This `if` form is -more similar to JavaScript's ternary `?:` operator than to -JavaScript's `if`. It is an expression, not a statement, and it -produces a value, namely the result of the second or third argument. +{{index Booleano}} -{{index Boolean}} +Egg también se diferencia de JavaScript en como maneja el valor de la +condición para `if`. No tratará cosas como cero o la cadena vacía como +falso, solamente el valor exacto `false`. -Egg also differs from JavaScript in how it handles the condition value -to `if`. It will not treat things like zero or the empty string as -false, only the precise value `false`. +{{index "evaluación en corto circuito"}} -{{index "short-circuit evaluation"}} +La razón por la que necesitamos representar `if` como una forma especial, +en vez de como una función regular, es que todos los argumentos de las +funciones son evaluados antes de que la función sea llamada, mientras +que el `if` debe evaluar solo el segundo _o_ el tercer argumento, +dependiendo del valor del primero. -The reason we need to represent `if` as a special form, rather than a -regular function, is that all arguments to functions are evaluated -before the function is called, whereas `if` should evaluate only -_either_ its second or its third argument, depending on the value of -the first. +La forma `while` es similar. -The `while` form is similar. ```{includeCode: true} specialForms.while = (args, scope) => { @@ -407,12 +407,13 @@ specialForms.while = (args, scope) => { }; ``` -Another basic building block is `hacer`, which executes all its arguments -from top to bottom. Its value is the value produced by the last -argument. +Otro bloque de construcción principal es `do`, que ejecuta todos sus argumentos +de arriba hacia abajo. Su valos es el valorr producido por el último +argumento. + ```{includeCode: true} -specialForms.hacer = (args, scope) => { +specialForms.do = (args, scope) => { let value = false; for (let arg of args) { value = evaluate(arg, scope); @@ -421,19 +422,20 @@ specialForms.hacer = (args, scope) => { }; ``` -{{index "= operator"}} +{{index "operador ="}} + +Para ser capaces de crear ((asignaciones)) y darle nuevos valores, +además necesitamos crear una forma llamada `define`. Espera una palabra +como prime argumento y una expresión producciendo un valor para asignar +a esa palabra como segundo argumento. Ya que `define`, como todo, +es una expresión, debe regresar un valor. Haremos que regrese el valor que +fue asignado (justo como el operador `=` de JavaScript). -To be able to create ((binding))s and give them new values, we also -create a form called `definir`. It expects a word as its first argument -and an expression producing the value to assign to that word as its -second argument. Since `definir`, like everything, is an expression, it -must return a value. We'll make it return the value that was assigned -(just like JavaScript's `=` operator). ```{includeCode: true} -specialForms.definir = (args, scope) => { +specialForms.define = (args, scope) => { if (args.length != 2 || args[0].type != "word") { - throw new SyntaxError("Incorrect use of definir"); + throw new SyntaxError("Incorrect use of define"); } let value = evaluate(args[1], scope); scope[args[0].name] = value; @@ -441,19 +443,18 @@ specialForms.definir = (args, scope) => { }; ``` -## The environment +## El entorno -{{index "Egg language", "evaluate function"}} +{{index "lenguaje Egg", "evaluar función"}} -The ((scope)) accepted by `evaluate` is an object with properties -whose names correspond to binding names and whose values correspond to -the values those ((binding))s are bound to. Let's define an object to -represent the ((global scope)). +El ((ámbito)) aceptado por `evaluate` es un objeto con propiedades +de las que sus nombres corresponden a los nombres de las vinculaciones en el ámbito +y sus valores corresnponden a los valores de esos vínculos. Ahora definamos un objeto +para representar el ((ámbito global)). -To be able to use the `if` construct we just defined, we must have -access to ((Boolean)) values. Since there are only two Boolean values, -we do not need special syntax for them. We simply bind two names to -the values `true` and `false` and use those. +Para poder usar el constructo `if` que acabamos de definir, necesitamos acceder +a valores ((Booleano))s. Como solo hay dos valores Booleanos, no necesitamos una sintaxis +especial. Simplemente asociaremos dos nombres a los valores `true` y `false` y usaremos estos nombres. ```{includeCode: true} const topScope = Object.create(null); @@ -462,21 +463,21 @@ topScope.true = true; topScope.false = false; ``` -We can now evaluate a simple expression that negates a Boolean value. +Podemos evaluar una expresión simple que niegue un Booleano. ``` -let prog = parse(`si(true, false, true)`); +let prog = parse(`if(true, false, true)`); console.log(evaluate(prog, topScope)); // → false ``` -{{index arithmetic, "Function constructor"}} +{{index aritmética, "constructor de Función"}} + +Para proveer la ((aritmética)) y ((operador))es de ((comparación)), +necesitamos además añadir algunas funciones al ((ámbito)). Para mantener +el código peequeño, usaremos `Function` para sintetizar varias +funciones de operador en un ciclo, en vez de definirlas individualmente. -To supply basic ((arithmetic)) and ((comparison)) ((operator))s, we -will also add some function values to the ((scope)). In the interest -of keeping the code short, we'll use `Function` to synthesize a bunch -of operator functions in a loop, instead of defining them -individually. ```{includeCode: true} for (let op of ["+", "-", "*", "/", "==", "<", ">"]) { @@ -484,65 +485,69 @@ for (let op of ["+", "-", "*", "/", "==", "<", ">"]) { } ``` -A way to ((output)) values is also very useful, so we'll wrap -`console.log` in a function and call it `imprimir`. +Tener una manera de ((devolver)) valores tambbién es muy útil, +así que envolveremos `console.log` en una función y la llamaremos +`print`. ```{includeCode: true} -topScope.imprimir = value => { +topScope.print = value => { console.log(value); return value; }; ``` -{{index parsing, "run function"}} +{{index parseo, "función run"}} + +Esto nos da suficientes herramientas elementales para escribir +programas simples. La siguiente función provee una forma conveniente +de leer un programa y correrlo en un ámbito nuevo. -That gives us enough elementary tools to write simple programs. The -following function provides a convenient way to parse a program and -run it in a fresh scope. ```{includeCode: true} -function run(programa) { - return evaluate(parse(programa), Object.create(topScope)); +function run(program) { + return evaluate(parse(program), Object.create(topScope)); } ``` -{{index "Object.create function", prototype}} +{{index "función Object.create", prototipo}} -We'll use object prototype chains to represent nested scopes, so that -the program can add bindings to its local scope without changing the -top-level scope. +Usareomos las cadenas de prototipos de los objetos para representar +ámbitos anidados, para que el programa pueda añadir asignaciones a su +ámbito local sin cambiar el ámbito superior. ``` run(` -hacer(definir(total, 0), - definir(count, 1), +do(define(total, 0), + define(count, 1), while(<(count, 11), - hacer(definir(total, +(total, count)), - definir(count, +(count, 1)))), - imprimir(total)) + do(define(total, +(total, count)), + define(count, +(count, 1)))), + print(total)) `); // → 55 ``` -{{index "summing example", "Egg language"}} +{{index "ejemplo de suma", "lenguaje Egg"}} + +Este es el programa que hemos visto varias veces antes, que calcula la suma +de los números del 1 a 10, expresado en Egg. Es claramente más +feo que su equivalente en JavaScript, peror no está tan mal para +un lenguaje implementado en menos de 150 ((líneas de código)). -This is the program we've seen several times before, which computes -the sum of the numbers 1 to 10, expressed in Egg. It is clearly uglier -than the equivalent JavaScript program—but not bad for a language -implemented in less than 150 ((lines of code)). {{id egg_fun}} -## Functions +## Funciones + +{{index función, "lenguaje Egg"}} -{{index function, "Egg language"}} +Un lenguaje de programación sin funciones es un lenguaje de +programación pobre, en efecto. -A programming language without functions is a poor programming -language indeed. +Afortunadamente, no es difícil agregar un constructo `fun`, +que trate su último argumento como el cuerpo de la función y use +todos los argumentos antes de ese como los parámetros de la función. -Fortunately, it isn't hard to add a `fun` construct, which treats its -last argument as the function's body and uses all arguments before -that as the names of the function's parameters. ```{includeCode: true} specialForms.fun = (args, scope) => { @@ -570,22 +575,22 @@ specialForms.fun = (args, scope) => { }; ``` -{{index "local scope"}} +{{index "ámbito local"}} -Functions in Egg get their own local scope. The function produced by -the `fun` form creates this local scope and adds the argument bindings -to it. It then evaluates the function body in this scope and returns -the result. +Las funciones en Egg tienen su propio ámbito local. La función producida +por la forma `fun` crea este entorno local y agrega las asociaciones de +argumentos a este. Entonces evalúa el cuerpo de la función en este ámbito +y regresa el resultado. ```{startCode: true} run(` -hacer(definir(plusOne, fun(a, +(a, 1))), +do(define(plusOne, fun(a, +(a, 1))), imprimir(plusOne(10))) `); // → 11 run(` -hacer(definir(pow, fun(base, exp, +do(define(pow, fun(base, exp, si(==(exp, 0), 1, *(base, pow(base, -(exp, 1)))))), @@ -594,56 +599,59 @@ hacer(definir(pow, fun(base, exp, // → 1024 ``` -## Compilation +## Compilación -{{index interpretation, compilation}} +{{index interpretación, compilación}} -What we have built is an interpreter. During evaluation, it acts -directly on the representation of the program produced by the parser. +Lo que hemos construido es un intérprete. Durante la evaluación, actúa +directamente en la representación del programa producido por el +parseador. -{{index efficiency, performance}} -_Compilation_ is the process of adding another step between the -parsing and the running of a program, which transforms the program -into something that can be evaluated more efficiently by doing as much -work as possible in advance. For example, in well-designed languages -it is obvious, for each use of a ((binding)), which binding is being -referred to, without actually running the program. This can be used to -avoid looking up the binding by name every time it is accessed, -instead directly fetching it from some predetermined ((memory)) -location. +{{index eficiencia, rendimiento}} -Traditionally, ((compilation)) involves converting the program to -((machine code)), the raw format that a computer's processor can -execute. But any process that converts a program to a different -representation can be thought of as compilation. +La _Compilación_ es el proceso de añadir otro paso entre la lectura +del programa y su ejecución, que transforma el programa en algo que +pueda ser evaluado más eficientemente, haciendo la mayor cantidad +de trabajo posible por adelantado. Por ejemplo, en lenguajes bien +diseñados es obvio, para cada uso de una ((asignación)), a qué asignación +te estás refiriendo, sin correr el programa. Esto puede ser usado para +evitar buscar la asociación por nombbre cada vez que se usa, y, en vez de eso, +traer directamente el valor de una locación predeterminada de +((memoria)). -{{index simplicity, "Function constructor", transpilation}} +Tradicionalmente, la ((compilación)) implica convertir el programa +en ((código máquina)), el formato crudo que el procesador de la computadora +puede ejecutar. Pero puedes pensar en compilación como cualquier proceso +que convierta un programa en una representación diferente. -It would be possible to write an alternative ((evaluation)) strategy -for Egg, one that first converts the program to a JavaScript program, -uses `Function` to invoke the JavaScript compiler on it, and then runs -the result. When done right, this would make Egg run very fast while -still being quite simple to implement. +{{index simplicidad, "función constructor", transpilación}} -If you are interested in this topic and willing to spend some time on -it, I encourage you to try to implement such a compiler as an -exercise. +Sería posible escribir una estrategia de ((evaluación)) alternativa +para Egg, una que primero convierrta el programa a uno de JavaScript, +usa `Function` para invocar el compilador de JavaSctipt, y después correr +el resultado. Cuando se hace correctamente, esto haría que Egg +corrra muy rápiddo mientras todavía sigue siendo simple implementarlo. -## Cheating +Si estás interesado en este tema y dispuesto a gastar algo de tiempo, +te animo a que trates de implementar el compilador como ejercicio. -{{index "Egg language"}} +## Haciendo trampa + +{{index "lenguaje Egg"}} -When we defined `if` and `while`, you probably noticed that they were -more or less trivial wrappers around JavaScript's own `if` and -`while`. Similarly, the values in Egg are just regular old JavaScript -values. +Cuando definimos `id` y `while`, probablemente te diste cuenta de que son +más o menos envoltorios triviales alrededor de los `if` y `while` de +JavaScript. Similarmente, los valores en Egg son solo valores de +JavaScript comunes. + +Si comparas la implementación de Egg, construida soobre JavaScript, +con la cantidad de trabajo y complejidad requerida para +construir un lenguaje de programación directamente en la funcionalidad +pura y cruda provista por una máquina, la diferencia es grande. Sin embargo, +con suerte este ejemplo te dio un vistazo de la forma en +que un ((lenguaje de programación)) funciona. -If you compare the implementation of Egg, built on top of JavaScript, -with the amount of work and complexity required to build a programming -language directly on the raw functionality provided by a machine, the -difference is huge. Regardless, this example hopefully gave you an -impression of the way ((programming language))s work. And when it comes to getting something done, cheating is more effective than doing everything yourself. Though the toy language in @@ -711,14 +719,14 @@ topScope.length = "..."; topScope.element = "..."; run(` -hacer(definir(sum, fun(array, - hacer(definir(i, 0), - definir(sum, 0), +do(define(sum, fun(array, + do(define(i, 0), + define(sum, 0), while(<(i, length(array)), - hacer(definir(sum, +(sum, element(array, i))), - definir(i, +(i, 1)))), + do(define(sum, +(sum, element(array, i))), + define(i, +(i, 1)))), sum))), - imprimir(sum(array(1, 2, 3)))) + print(sum(array(1, 2, 3)))) `); // → 6 ``` @@ -756,8 +764,8 @@ binding `a`. ``` run(` -hacer(definir(f, fun(a, fun(b, +(a, b)))), - imprimir(f(4)(5))) +do(define(f, fun(a, fun(b, +(a, b)))), + print(f(4)(5))) `); // → 9 ``` @@ -819,6 +827,7 @@ console.log(parse("a # one\n # two\n()")); // operator: {type: "word", name: "a"}, // args: []} ``` + if}} {{hint @@ -888,6 +897,7 @@ hacer(definir(x, 4), run(`set(quux, true)`); // → Some kind of ReferenceError ``` + if}} {{hint