diff --git a/00_intro.txt b/00_intro.txt index 035bb1d57..6c37607cb 100644 --- a/00_intro.txt +++ b/00_intro.txt @@ -4,11 +4,11 @@ = Introducción = Este libro trata de como hacer que las ((computadoras)) hagan lo que tú quieres -que hagan. Las computadoras son tan comunes como los desatornilladores hoy en día, +que hagan. Las computadoras son tan comunes como los destornilladores hoy en día, pero tienen mucha más complejidad oculta y, por lo tanto, son más difíciles de operar y entender. Para muchos siguen siendo cosas extrañas, un poco amenazadoras. -image::img/generated/computer.png[alt="Comunicándose con una computadora"] +image::img/computer.svg[alt="Comunicándose con una computadora"] (((interfaz gráfica de usuario)))Hemos encontrado dos formas efectivas de cerrar la brecha ente nosotros, suaves organismos biológicos @@ -18,14 +18,14 @@ usar nuestros sentidos del mundo físico y construir interfaces que imitan ese mundo y nos permiten manipular figuras en una pantalla con nuestros dedos. Esto funciona muy bien para interacciones casuales con la máquina. -(((lenguage de programación)))Pero aún no hemos encontrado una buena forma +(((lenguaje de programación)))Pero aún no hemos encontrado una buena forma de usar la interfaz gráfica para comunicar a la computadora cosas que el diseñador de interfaces no anticipó. Para interfaces abiertas, como indicarle a la computadora que ejecute tareas arbitrarias, hemos tenido más suerte con otra estrategia, que hace uso de nuestro talento para el lenguaje: enseñarle a la computadora uno. -(((lengiajes humanos)))(((expresividad)))Los lenguajes humanos permiten que +(((lenguajes humanos)))(((expresividad)))Los lenguajes humanos permiten que palabras y frases se combinen en muchas diferentes formas, lo cuál nos permite decir una amplia variedad de cosas. Los lenguajes computacionales, aunque son gramaticalmente menos flexibles, siguen un principio similar. @@ -56,7 +56,7 @@ ____ (((programación,dificultad de)))A parte de explicar JavaScript, te introduciré en los principios básicos de la programación. Programar, resulta, es difícil. Las reglas fundamentales típicamente son simples y claras. -Pero los programas contruidos sobre esas reglas tienden a volverse +Pero los programas construidos sobre esas reglas tienden a volverse lo suficientemente complejos para introducir sus propias reglas y más complejidad. En cierta forma, estás construyendo tu propio laberinto y podrías perderte en él. @@ -68,7 +68,7 @@ formas que requerirán que hagas conexiones adicionales. Es tu responsabilidad realizar el esfuerzo necesario. Cuando se te haga difícil seguir este libro, no concluyas rápidamente nada acerca de tus capacidades. -Tu eres bueno—sólo necesitas mantener el paso. Toma un respiro, +Tu eres bueno, sólo necesitas mantener el paso. Toma un respiro, vuelve a leer el material, y _siempre_ asegúrate de leer y entender los programas de ejemplo y los ((ejercicios)). Aprender es un trabajo duro, pero todo lo que aprendas ahora es tuyo y hará el aprendizaje cada vez más fácil. @@ -81,24 +81,23 @@ virtualmente ilimitada pueden ser creados en la forma de programas de computador ____ (((programa,naturaleza de un)))(((datos)))Un programa es muchas cosas. Es una -pieza de texto escrita por un programador, es la fuerza que dirije +pieza de texto escrita por un programador, es la fuerza que dirige a la computadora para hacer lo que hace, son datos en la memoria de la computadora, y aún así controla las acciones realizadas en esta misma memoria. Las analogías que tratan de comparar a las computadoras con objetos que conocemos tienden a quedarse cortas. Una que se ajusta superficialmente es la de -máquina, un montón de piezas separdas que se relacionan, y para hacerlo -funcionar, tenemos que considerar las formas en que esas piezas se -interconectan y contribuyen al funcionamiento del todo. +máquina, un montón de piezas separadas que se relacionan, y para hacerlo +funcionar, tenemos que considerar las formas en que esas piezas se interconectan y contribuyen al funcionamiento del todo. -(((computadora)))Una computadora es una máquina que actua como anfitriona de +(((computadora)))Una computadora es una máquina que actuá como anfitriona de estas máquinas inmateriales. Las computadoras por sí mismas sólo pueden hacer cosas estúpidamente simples. La razón por la que son tan poderosas es que hacen esas cosas a una velocidad increíblemente rápida. Un programa puede combinar ingeniosamente un número enorme de esas acciones simples para lograr cosas muy complicadas. -(((progración,lo bueno de)))Para algunos de nosotros, escribir programas de -computadoras es un juego fascinante. Un programa es un construcción del +(((programación,lo bueno de)))Para algunos de nosotros, escribir programas de +computadoras es un juego fascinante. Un programa es una construcción del pensamiento. No tiene costo construirlo, no pesa nada, y crece fácilmente bajo nuestras manos tecleando. @@ -131,7 +130,7 @@ olvidarán su alegría, y se aburrirán con su trabajo. (((lenguaje de programación)))(((código máquina)))(((datos binarios)))En el principio, cuando nació la computación, no había lenguajes de programación. -Los progrmas lucían algo así: +Los programas lucían algo así: ---- 00110001 00000000 00000000 @@ -226,9 +225,9 @@ console.log(total); (((bucle while)))(((bucle)))Esta versión nos da unas cuantas mejoras más. Y lo más importante es que ya no hay necesidad de especificar la forma en que queremos que nuestro programa salte de atrás para adelante. La construcción del -lenguaje `while` se encarga de eso. Continúa ejecutándo el bloque (dentro de las +lenguaje `while` se encarga de eso. Continúa ejecutando el bloque (dentro de las llaves) debajo de él mientras la condición que se le dio se mantenga. Esa -condición es `conteo <= 10`, lo que significa "++conteo++ es menor o igual que 10". +condición es `conteo <= 10`, lo que significa "++conteo++ es menor o igual que 10". Ya no tenemos que crear un valor temporal y compararlo con 0, lo cuál era un detalle sin interés para nosotros. Parte del poder de los lenguajes de programación es que estos se encargan de los detalles que no nos interesan. @@ -317,7 +316,7 @@ JavaScript realmente me ha _gustado_. (((futuro)))(((JavaScript,versiones de)))(((ECMAScript)))(((ECMAScript 6)))Han existido varias versiones de JavaScript. ECMAScript versión 3 fue la -versión ampliamente soportada en la época de ascención a la dominación de +versión ampliamente soportada en la época de ascensión a la dominación de JavaScript, más o menos entre 2000 y 2010. Durante este tiempo, el trabajo fue dirigido a una ambiciosa versión 4, que planeaba varias mejoras radicales y extensiones al lenguaje. Cambiar un lenguaje vivo, ampliamente usado en una @@ -339,25 +338,25 @@ del navegador. == Código, y qué hacer con él == -(((leyenfo código)))(((escribiendo código)))El código es el texto del que están +(((leyendo código)))(((escribiendo código)))El código es el texto del que están compuestos los programas. La mayor parte de los capítulos de este libro contienen un montón de él. En mi experiencia, leer y escribir ((código)) son partes indispensables de ((aprender)) a programar, así que trata de no sólo darles una -mirada rápida a los ejemplos. Léelos aténtamente y entiéndelos. Esto podría ser +mirada rápida a los ejemplos. Léelos atentamente y entiéndelos. Esto podría ser lento y confuso al principio, pero prometo que rápidamente le agarrarás el modo. Lo mismo es aplicable a los ((ejercicios)). No asumas que los entiendes hasta -que realemente hayas escrito una solución que funcione. +que realmente hayas escrito una solución que funcione. (((interpretación))) Te recomiendo probar tus soluciones a los ejercicios en un intérprete de JavaScript real. De esa forma obtendrás retroalimentación inmediata acerca de si lo que estás haciendo funciona, y, yo espero, serás -tentado a ((experimentar)) e ir más allás de los ejercicios. +tentado a ((experimentar)) e ir más allá de los ejercicios. ifdef::interactive_target[] Cuando estés leyendo este libro en tu navegador, puedes editar(y correr) -todos los programas de ejemplo haciendo click en ellos. +todos los programas de ejemplo haciendo clic en ellos. endif::interactive_target[] @@ -366,7 +365,7 @@ ifdef::book_target[] (((descarga)))(((sandbox)))(((código funcionando)))La manera más fácil de correr el código del libro, y de experimentar con él, es en la versión web en http://eloquentjavascript.net/[_eloquentjavascript.net_]. Ahí podrás -hacer click en un ejemplo para editarlo y correrlo y para ver la salida que +hacer clic en un ejemplo para editarlo y correrlo y para ver la salida que produce. Para trabajar en lo ejercicios, dirígete a http://eloquentjavascript.net/code[_eloquentjavascript.net/code_], que provee código para empezar con cada ejercicio y te permite ver las soluciones. @@ -385,7 +384,7 @@ necesarios para hacer funcionar el código de cualquier capítulo. == Vista general del libro == -Este libro está compuesto por tres aprtes. Los primeros 11 capítulos hablan de +Este libro está compuesto por tres partes. Los primeros 11 capítulos hablan de JavaScript en sí mismo. Los siguientes ocho son acerca de los ((navegadores)) web y la forma en que JavaScript es usado para programarlos. Finalmente, los últimos dos capítulos están dedicados a ((Node.js)), otro entorno para @@ -393,7 +392,7 @@ programar en JavaScript. A lo largo del libro hay cinco _capítulos de proyecto_, que describen programas de ejemplo más grandes para darte una prueba de la programación en el mundo real. -En order de aparcición trabajaremos en +En orden de aparición trabajaremos en link:07_elife.html#elife[simulación de vida artificial], un link:11_language.html#language[lenguaje de programación], un link:15_game.html#game[juego de plataforma], un @@ -403,9 +402,9 @@ link:21_skillsharing.html#skillsharing[sitio dinámico]. La parte del lenguaje del libro empieza con cuatro capítulos para presentar la estructura básica de JavaScript. Estos presentan link:02_program_structure.html#program_structure[estructuras de control] -(como la palabra `while` que viste ene esta introducción), +(como la palabra `while` que viste en esta introducción), link:03_functions.html#functions[funciones] (escribir tus propias operaciones), -y link:04_data.html#data[estructuras de datos]. Despeués de esto, serás capaz de +y link:04_data.html#data[estructuras de datos]. Después de esto, serás capaz de escribir programas simples. Después, los capítulos link:05_higher_order.html#higher_order[5] y link:06_object.html#object[6] presentan técnicas para usar @@ -414,8 +413,8 @@ mantener a la complejidad bajo control. Después de link:07_elife.html#elife[un primer capítulo de proyecto], la primera parte del libro continúa con capítulos acerca de -link:08_error.html#error[manejo y correccón de errores], -link:09_regexp.html#regexp[expresiones regulares] (una herramienta importanate +link:08_error.html#error[manejo y corrección de errores], +link:09_regexp.html#regexp[expresiones regulares] (una herramienta importante para el manejo de datos de texto), y link:10_modules.html#modules[modularidad], otra arma contra la complejidad. El link:11_language.html#language[segundo capítulo de proyecto] termina con la @@ -425,7 +424,7 @@ En la segunda parte, los Capítulos link:12_browser.html#browser[12] a link:19_paint.html#paint[19], describen las herramientas a las que JavaScript tiene acceso en el navegador web. Aprenderás a mostrar cosas en la pantalla (Capítulos link:13_dom.html#dom[13] y -link:16_canvas.html#canvas[16]), repsonder a los datos de entrada del usuario +link:16_canvas.html#canvas[16]), responder a los datos de entrada del usuario (Capítulos link:14_event.html#event[14] y link:18_forms.html#forms[18]), y a comunicarte a través de la red (link:17_http.html#http[Capítulo 17]). Otra vez, hay dos proyectos en esta parte. diff --git a/01_values.txt b/01_values.txt index a4a44d5e6..d32916648 100644 --- a/01_values.txt +++ b/01_values.txt @@ -243,7 +243,7 @@ cadenas de texto mientras coincidan al principio y al final. cosa puede estar entre comillas, y JavaScript creará una cadena. Pero unos cuantos caracteres son un poco difíciles. Puedes imaginar que poner comillas dentro de comillas puede ser difícil. _Newlines_ (el carácter -salto de línea, lo que obtines cuando presionas Enter), tampoco puede +salto de línea, lo que obtienes cuando presionas Enter), tampoco puede ser introducido entre comillas. La cadena tiene que permanecer en una sola línea. @@ -296,7 +296,7 @@ cadenas. La siguiente línea produce la cadena `"concatenar"`: Hay más maneras de manipular las cadenas, de las que hablaremos cuando lleguemos a los métodos en el link:04_data.html#methods[Capítulo 4]. -== Operadores Unitario == +== Operadores unarios == (((operador)))(((operador typeof)))(((tipo)))No todos los operadores son símbolos. Algunos son escritos como palabras. Un ejemplo es el @@ -323,8 +323,8 @@ estés corriendo el programa. binario))) Los otros operadores que hemos visto operaban sobre dos valores, pero `typeof` sólamente toma uno. Los operadores que usan dos valores son llamados operadores _binarios_, mientras que aquellos -que sólo toman uno son llamados operadores _unitarios_. El operador menos -puede usar tanto como operador binario como operador unitario. +que sólo toman uno son llamados operadores _unarios_. El operador menos +puede usar tanto como operador binario como operador unario. [source,javascript] ---- @@ -371,7 +371,7 @@ es más o menos alfabética: las letras mayúsculas son siempre "menores" que las minúsculas, así que `"Z" < "a"` es verdad, y los caracteres no alfabéticos (!, -, y así por el estilo) son también incluidos en el ordenamiento. La comparación real está basada en el estándar -_((Unicode))_. Este estándar asigna un número a virtualemente cada +_((Unicode))_. Este estándar asigna un número virtualmente a cada carácter que alguna vez necesitarás, incluyendo caracteres del griego, árabe, japonés, tamil, y otros alfabetos. Tener tales números es útil para guardar las cadenas de texto dentro de la computadora porque @@ -390,7 +390,7 @@ console.log("Itchy" != "Scratchy") // → true ---- -(((comparaciéon,de NaN)))(((NaN)))Sólo esxiste un valor en JavaScript +(((comparaciéon,de NaN)))(((NaN)))Sólo existe un valor en JavaScript que no es igual a sí mismo, y este es `NaN`, que significa "no es un número". @@ -455,7 +455,7 @@ paréntesis como sea posible: (((ejecución condicional)))(((operador ternario)))(((operador ?: )))(((operador condicional)))(((caracter dos puntos)))(((signo de -interrogación)))El último operador lógico del que hablaré no es unitario, +interrogación)))El último operador lógico del que hablaré no es unario, ni binario, sino _ternario_, opera en tres valores. Este es escrito con un símbolo de interrogación y dos puntos, como sigue: @@ -509,7 +509,7 @@ console.log(false == 0) // → true ---- -(((operador +)))(((aritmética)))(((pass:[*] operador)))(((operador +(((operador +)))(((aritmética)))(((pass:[\*] operador)))(((operador -)))Cuando un operador es aplicado al tipo "incorrecto" de valor, JavaScript convertirá silenciosamente el valor en el tipo de dato que espera, usando un conjunto de reglas que a menudo no son lo que @@ -625,7 +625,7 @@ valor (`13`, `"abc"`). Puedes combinar y transformar valores con los operadores. Vimos operadores binarios para aritmética(`+`, `-`, `*`, `/` y `%`), concatenación de cadenas (`+`), comparación (`==`, `!=`, `===`, `!==`, `<`, `>`, `<=`, `>=`), y lógica -(`&&`, `||`), así como varios operadores unitarios (`-` para hacer +(`&&`, `||`), así como varios operadores unarios (`-` para hacer negativo un número, `!` para negar lógicamente y `typeof` para obtener el tipo de un valor) y un operador ternario (`?:`) para elegir entre dos valores basándonos en un tercero. diff --git a/02_program_structure.txt b/02_program_structure.txt index e9b5ed46d..847fdc1d8 100644 --- a/02_program_structure.txt +++ b/02_program_structure.txt @@ -9,7 +9,7 @@ ____ Y mi corazón brilla rojo debajo de mi delgada, translúcida piel y tienen que administrarme 10cc de JavaScript -para hacerme regresar. (Responsdo bien a las toxinas en la sangre.) ¡Hombre, +para hacerme regresar (respondo bien a las toxinas en la sangre). ¡Hombre, esa cosa te sacará de tus casillas! ____ @@ -21,33 +21,34 @@ hasta el punto en que podamos expresar alguna prosa significativa. == Expresiones y declaraciones == -(((grammar)))(((syntax)))(((code,structure -of)))(((grammar)))(((JavaScript,syntax)))En el +(((gramática)))(((sintaxis)))(((código, +estructura de)))(((gramática)))(((JavaScript,sintaxis)))En el link:01_values.html#values[Capítulo 1], creamos algunos valores y después -les aplicamos operadores para obtener nuevos valores. Creando valores como éste +les aplicamos operadores para obtener nuevos valores. Crear valores de esta forma es una parte esencial de cada programa de JavaScript, pero esto es sólo una parte. -(((literal expression)))Un fragmento de código que produce un valor es +(((expresión literal)))Un fragmento de código que produce un valor es llamado una _((expresión))_. Cada valor que se escribe literalmente (tal como `22` o `"psicoanálisis"`) es una expresión. Una expresión -entre ((paréntesis)) es también una expresión, como es un ((operador +entre ((paréntesis)) es también una expresión, como un ((operador binario)) aplicado a dos expresiones o un operador unario aplicado a -uno. +una expresion. -(((nesting,of expressions)))(((human language)))Esto muestra parte de la -belleza de una interfaz basada en el lenguaje. Las expresiones se puede anidar en una forma -muy similar a la forma de sub-frases en la que las lenguas humanas son anidada, y -las sub-frase puede contener sus propias sub-frases, etc. Esto nos permite -combinar expresiones para expresar cálculos arbitrariamente complejos. +(((anidado de instrucciones)))(((lenguage humano)))Esto muestra parte de la +belleza de una interfaz basada en el lenguaje. Las expresiones se pueden anidar +en una forma muy similar a la forma de sub-frases en la que las lenguas humanas +son anidadas, y las sub-frases pueden contener sus propias sub-frases, etc. +Esto nos permite combinar expresiones para expresar cálculos +arbitrariamente complejos. -(((statement)))(((semicolon)))(((program)))Si una expresión +(((declaración)))(((punto y coma)))(((programa)))Si una expresión corresponde a un fragmento de frase, una _declaración_ en JavaScript corresponde a una frase completa en un lenguaje humano. Un programa es simplemente una lista de declaraciones. (((syntax)))El tipo más simple de declaración es una expresión con un -punto y coma después de ella. Se trata de un programa: +punto y coma después de ella. Esto es un programa: [source,javascript] ---- @@ -55,50 +56,50 @@ punto y coma después de ella. Se trata de un programa: !false; ---- -Es un programa inútil, sin embargo. Una ((expresión)) puede ser contenida -solo de producir un valor, que puede entonces ser utilizado por the "enclosing -expression". Una ((declaración)) destaca por su cuenta y que equivale a algo -sólo si afecta al mundo. Se podría mostrar algo en la -pantalla que cuenta como cambiar el mundo o podría cambiar el -estado interno de la máquina de una manera que afectará los estados -que vienen despues de él. Estos cambios se llaman _((efecto colateral))s_. Las -declaraciones en el ejemplo anterior solo producen los valores `1` y -`verdadero` y después los tiran inmediatamente. Esto no deja ninguna impresión -en el mundo en absoluto. Al ejecutar el programa, nada observable -sucede. - -(((programming style)))(((automatic semicolon -insertion)))(((semicolon)))En algunos casos, JavaScript le permite -omitir el punto y coma al final de una instrucción. En otros casos, tiene que -estar allí, o el siguiente ((linea)) serán tratados como parte de la misma +Sin embargo, es un programa inútil. Una ((expresión)) puede estar presente para +sólo producir un valor, que puede entonces ser utilizado por la expresión que +la contiene. Una ((declaración)) existe por sí sola y que equivale a algo +sólo si afecta al mundo. Podría mostrar algo en la +pantalla -que cuenta como cambiar el mundo_ o podría cambiar el +estado interno de la máquina de estados de manera que afectará las +declaraciones que vienen despues de ella. Estos cambios se +llaman _((efectos colaterale))s_. Las declaraciones en el ejemplo anterior solo +producen los valores `1` y `verdadero` y los desechan inmediatamente. +Esto no deja ningún cambio en el mundo en absoluto. Al ejecutar el programa, +nada observable sucede. + +(((estilos de programación)))(((inserción automática de punto +y coma)))(((punto y coma)))En algunos casos, JavaScript te permite +omitir el punto y coma al final de una declaración. En otros casos, tiene que +estar allí, o la siguiente ((linea)) será tratada como parte de la misma declaración. Las reglas para cuando se puede omitir con seguridad son algo -complejo y propenso a errores. En este libro, cada declaración que necesita un -punto y coma siempre será terminada por uno. Te recomiendo que hagas lo -misma en sus propios programas, al menos hasta que haya aprendido más sobre +complejas y propensas a errores. En este libro, cada declaración que necesite un +punto y coma siempre será terminada por un punto y coma. Te recomiendo que hagas lo +mismo en tus propios programas, al menos hasta que hayas aprendido más sobre sutilezas involucradas en omitir el punto y coma. == Variables == -(((syntax)))(((variable,definition)))(((side effect)))(((memory))) ¿Cómo -un programa de mantener un estado ((estado))? ¿Cómo recuerda -cosas? Hemos visto cómo producir nuevos valores de viejos valores, pero +(((sintaxis)))(((variable, definición)))(((efecto secundario)))(((memoria))) ¿Cómo +mantiene un programa su ((estado)) interno? ¿Cómo recuerda algo? +Hemos visto cómo producir nuevos valores de viejos valores, pero esto no cambia los valores antiguos, y el nuevo valor tiene que ser inmediatamente utilizado o se disipará de nuevo. Para atrapar y mantener los valores, JavaScript proporciona una cosa llamada _variable_. [source,javascript] ---- -var caught = 5 * 5; +var atrapado = 5 * 5; ---- -(((var keyword)))Y eso nos da nuestra segunda clase de ((declaración)). -La palabra especial (_((keyword))_) `var` indica que esta frase -va a definir una variable. Es seguido por el nombre de la variable +(((palabra clave var)))Y eso nos da nuestra segunda clase de ((declaración)). +La palabra especial(_((palabra clave))_ o _((keyword))_) `var` indica que +esta frase va a definir una variable. Es seguida por el nombre de la variable y, si queremos dar de inmediato un valor, con un operador de `=` y una expresión. -La declaración anterior crea una variable llamada `caught` y se usa -para agarrar el número que se produce al multiplicar 5 por 5. +La declaración anterior crea una variable llamada `atrapado` y se usa +para retener el número que se produce al multiplicar 5 por 5. Después de que una variable se ha definido, su nombre puede ser usado como una ((expresión)). El valor de esa expresión es el valor que la @@ -106,81 +107,82 @@ variable alberga actualmente. He aquí un ejemplo: [source,javascript] ---- -var ten = 10; -console.log(ten * ten); +var diez = 10; +console.log(diez * diez); // → 100 ---- -(((subrayar el carácter)))(((signo de -dólar)))(((variable,naming)))Los nombres de variables pueden ser cualquier palabra que no es -una palabra reservada (tal como `var`). Ellos no pueden incluir espacios. -Dígitos también pueden ser parte de la variable nombre—`catch22` es un nombre válido, -por ejemplo-, pero el nombre no debe comenzar con un dígito. Un nombre de variable -no puede incluir puntuacion, a excepción de los caracteres `$` y `_`. +(((carácter guión bajo)))(((signo de +dólar)))(((variable,naming)))Los nombres de variables pueden ser cualquier +palabra que no sea una palabra clave (tal como `var`). Estos no pueden incluir +espacios. Los dígitos también pueden ser parte de la variable nombre —`catch22` +es un nombre válido, por ejemplo-, pero el nombre no debe comenzar con un dígito. +Un nombre de variable no puede incluir puntuación, a excepción de los caracteres +`$` y `_`. -(((= operator)))(((assignment)))(((variable,assignment))Cuando una -variable apunta a un valor, eso no quiere decir que está ligado a ese -valor para siempre. El operador de `=` se puede utilizar en cualquier momento en variables -existentes para desconectarlas de su valor actual y etenerlas -apuntando a una nueva. +(((operador =)))(((asignación)))(((variable,asiganción))Cuando una +variable apunta a un valor, eso no quiere decir que está ligada a ese +valor para siempre. El operador `=` se puede utilizar en cualquier momento +en variables existentes para desconectarlas de su valor actual y apuntarlas +a uno nuevo. [source,javascript] ---- -var mood = "light"; -console.log(mood); -// → light -mood = "dark"; -console.log(mood); -// → dark +var tono = "claro"; +console.log(tono); +// → claro +tono = "oscuro"; +console.log(tono); +// → oscuro ---- -(((variable,modelo of)))(((tentáculo (analogía)))) Debieras -imaginar variables como tentáculos, en lugar de las cajas. Ellas no -_contienen _ valores; ellas _grasp_ them—two variables pueden referirse la -mismo valor. Un programa puede acceder sólo los valores que todavía tiene a -hold on. Cuando usted necesita recordar algo, haces crecer un tentáculo para -afferarse a ello or you reattach one of your existing tentacles to it. +(((variable,modelo de)))(((tentáculo (analogía)))) Podrías +imaginar las variables como tentáculos, en lugar de la cajas. Estas no +_contienen_ valores; los _agarran_; dos variables pueden referirse al +mismo valor. Un programa puede acceder sólo los valores que todavía mantiene detenidos. +Cuando necesitas recordar algo, haces crecer un tentáculo para +agarrarlo o cambias unos de tus tentáculos existentes para agarrarlo. image::img/octopus.jpg[alt="Variables as tentacles"] Veamos un ejemplo. Para recordar el número de dólares que Luigi -aún te debe, se crea una variable. Y luego, cuando él te paga $ 35, -tu das a esta variable un valor nuevo. +aún te debe, se crea una variable. Y luego, cuando te paga $35, +le das a esta variable un valor nuevo. [source,javascript] ---- -var luigisDebt = 140; -luigisDebt = luigisDebt - 35; -console.log(luigisDebt); +var deudaDeLuigi = 140; +deudaDeLuigi = deudaDeLuigi - 35; +console.log(deudaDeLuigi); // → 105 ---- (((indefinido)))Cuando se define una variable sin darle un valor, -el tentáculo no tiene nada de que enteder, por lo que termina en el aire. Si le preguntas -por el valor de una variable vacía, obtendrá el valor de `undefined (indefinido)`. +el tentáculo no tiene nada que sostener, por lo que termina en el aire. Si preguntas +por el valor de una variable vacía, obtendrás el valor `undefined` (indefinido). -(((var keyword)))Una sola `var` declaración puede definir múltiples -variables. Las definiciones deben estar separados por comas. +(((var keyword)))Una sola declaración `var` puede definir múltiples +variables. Las definiciones deben estar separadas por comas. [source,javascript] ---- -var one = 1, two = 2; -console.log(one + two); +var uno = 1, dos = 2; +console.log(uno + dos); // → 3 ---- == Palabras clave y palabras reservadas == -(((syntax)))(((implementos (palabra reservada))))(((interfaz (palabra -reservada))))(((dejar palabras clave)))(((paquete (palabra reservada))))(((privado -(palabra reservada))))(((protegido (palabra reservada))))(((publico (palabra -reservada))))(((statico (palabra reservada))))(((operador vacío)))(((yield -(palabra reservada))))(((palabra reservada)))(((variable,naming)))Palabras con -un significado especial, como `var`, son _((palabra reservada))s_, y no se pueden ser +(((sintaxis)))(((implements (palabra reservada))))(((interface (palabra +reservada))))(((let (palabra reservada))))(((package (palabra reservada))))(((private +(palabra reservada))))(((protected (palabra reservada))))(((public (palabra +reservada))))(((static (palabra reservada))))(((operador vacío)))(((yield +(palabra reservada))))(((palabra reservada)))(((variable, nombrado)))Palabras con +un significado especial, como `var`, son _((palabras clave))_, y no pueden ser utilizadas como nombres de variables. También hay un número de palabras que son -“reservado para uso” en ((futuras)) versiones de JavaScript. Estos también -oficialmente no pueden ser utilizados como nombres de variables, aunque algunos -entornos de JavaScript hacen que puedan. La lista completa de palabras clave y +“reservadas para uso” en ((futuras)) versiones de JavaScript. Estas también +están oficialmente no permitidas como nombres de variables, aunque algunos +entornos de JavaScript las permiten. La lista completa de palabras clave y palabras reservadas es bastante larga. [source,text/plain] @@ -193,98 +195,97 @@ protected public return static super switch this throw true try typeof var void while with yield ---- -No te preocupes por la memorización de estos, pero recuerda que esto podría ser -el problema cuando una definición de variable no funciona como se esperaba. +No te preocupes por memorizarlas, pero recuerda que esto podría ser +el problema cuando una definición de variable no funcione como se esperaba. == El entorno == (((entorno estándar)))La colección de variables y sus valores -que existe en un momento dado se llama el _((entorno))_. cuando una +que existe en un momento dado se llama el _((entorno))_. Cuando un programa se pone en marcha, este entorno no está vacío. Siempre contiene -variables que forman parte de la lenguaje ((estándar)), y la mayoría de la -tiempo, tiene variables que proporcionan formas de interactuar con el -sistema de alrededores. por ejemplo, en un ((navegador)), hay variables +variables que forman parte del lenguaje ((estándar)), y la mayoría del +tiempo, contiene variables que proporcionan formas de interactuar con el +sistema que lo contiene. Por ejemplo, en un ((navegador)), existen variables y funciones para inspeccionar e influir en la página web cargada en ese momento -y leer ((ratón)) and ((teclado)) entrada. +y leer entrada del ((ratón)) y del ((teclado)). == Funciones == -indexsee:[application (of functions),function application] -indexsee:[invoking (of functions),function application] -indexsee:[calling (of functions),function application] -(((output)))(((function)))(((function,application)))(((alert -function)))(((message box)))Una gran cantidad de los valores proporcionada en el -entorno por defecto tienen el tipo _((funcion))_. Una función es un -pedazo de programa envuelto en un valor. Tales valores pueden ser _aplicado_ con -el fin de ejecutar el programa envuelta. Por ejemplo, en un ((navegador)) -entorno, la variable `alert` ejerce una función que muestra un poco -((cuadro de diálogo)) con un mensaje. Se utiliza como esto: +indexsee:[aplicación (de funciones),función de aplicación] +indexsee:[invocación (de funciones),función de aplicación] +indexsee:[llamado (de funciones),función de aplicación] +(((salida)))(((función)))(((función,aplicación)))(((función +alert)))(((caja de mensaje)))Una gran cantidad de los valores proporcionados en el +entorno por defecto tienen el tipo _((function))_. Una función(function) es un +pedazo de programa encerrado en un valor. Tales valores pueden ser _aplicados_ con +el fin de ejecutar el programa envuelto. Por ejemplo, en un entorno de +((navegador)), la variable `alert` contiene una función que muestra un pequeño +((cuadro de diálogo)) con un mensaje. Se utiliza como sigue: [source,javascript] ---- -alert("Buenos días!"); +alert("¡Good Morning!"); ---- image::img/alert.png[alt="An alert dialog",width="8cm"] -(((parameter)))(((function,application)))La ejecución de una función se -llamado _invoking_, _llamar_, or _aplicar_ la. Usted puede llamar a un -función poniendo ((paréntesis)) después de una expresión que produce una -valor de la función. Por lo general, vamos a usar directamente el nombre de la variable -que mantiene la función de. Los valores entre paréntesis le dan a -el programa dentro de la función. En el ejemplo, la funcion de `alert` +(((parametro)))(((función,aplicación)))La ejecución de una función es denominada +_invocar_, _llamar_, o _aplicar_ la función. Puedes llamar a una +función poniendo ((paréntesis)) después de una expresión que produce un +valor de la función. Por lo general, se usa directamente el nombre de la variable +que contiene la función. Los valores entre paréntesis se le pasan a +el programa dentro de la función. En el ejemplo, la función `alert` utiliza la cadena que le damos como el texto que se mostrará en el cuadro de diálogo. -Los valores dados a las funciones se denominan _((argumento))s_. La funcion -de `alert` necesita solo uno de ellos, pero otras funciones pueden necesitar un +Los valores dados a las funciones se denominan _((argumento))s_. La función `alert` +necesita solo uno, pero otras funciones pueden necesitar un número diferente o diferentes tipos de argumentos. -== The console.log function == - -(((JavaScript console)))(((developer -tools)))(((Node.js)))(((console.log)))(((output)))The `alert` function -can be useful as an output device when experimenting, but clicking -away all those little windows will get on your nerves. In past -examples, we've used `console.log` to output values. Most JavaScript -systems (including all modern web ((browser))s and Node.js) provide a -`console.log` function that writes out its arguments to _some_ text -output device. In browsers, the output lands in the ((JavaScript -console)). This part of the browser interface is hidden by default, -but most browsers open it when you press F12 or, on Mac, when you -press Command-Option-I. If that does not work, search through the -menus for an item named “web console” or “developer tools”. +== La función console.log == + +(((consola de JavaScript)))(((developer +tools)))(((Node.js)))(((console.log)))(((salida)))(((output)))La función `alert` +puede ser útil para imprimir cuando estamos experimentando, pero quitar del camino +todas esas pequeñas ventanas puede desesperarte. En ejemplos pasados, hemos usado +`console.log` para devolver valores. La mayoría sistemas JavaScript (incluyendo a +todos los ((navegador))es web modernos y a Node.js) nos dan una función `console.log` +que imprime sus argumentos en _algún_ dispositivo de salida de texto. En los navegadores +la salida queda en la ((consola de JavaScript)). Esta parte del navegador está +escondida por defecto, pero la mayoría de los navegadores la abren cuando presionas +F12 o, en Mac, cuando presionas Command-Option-I. Si esto no funciona, busca en los +menús un item llamado "Consola Web" o "Herramientas de Desarrollador". + ifdef::interactive_target[] -When running the examples, or your own code, on the pages of this -book, `console.log` output will be shown after the example, instead of -in the browser's JavaScript console. +Cuando corras los ejemplos, o tu propio código, en las páginas de este libro, +la salida de `console.log` será mostrada después del ejemplo, en vez de en la +consola de JavaScript del navegador. endif::interactive_target[] [source,javascript] ---- var x = 30; -console.log("the value of x is", x); -// → the value of x is 30 +console.log("el valor de x es", x); +// → el valor de x es 30 ---- -(((object)))Though ((variable)) names cannot contain ((period -character))s, `console.log` clearly has one. This is because -`console.log` isn't a simple variable. It is actually an expression -that retrieves the `log` ((property)) from the value held by the -`console` variable. We will find out exactly what this means in -link:04_data.html#properties[Chapter 4]. +(((objeto)))Aunque los nombres de ((variable)) no pueden contener +el ((caracter punto)), `console.log` claramente tiene uno. Esto es +porque `console.log` no es una variable simple. Es en realidad una +expresión que trae la propiedad `log` del valor mantenido por la +variable `console`. Veremos que significa exactamente en el +link:04_data.html#properties[Capítulo 4]. [[return_values]] -== Return values == +== Valores de Retorno == -(((comparison,of numbers)))(((return value)))(((Math.max -function)))(((maximum)))Showing a dialog box or writing text to -the screen is a _((side effect))_. A lot of functions are useful -because of the side effects they produce. Functions may also produce -values, and in that case, they don't need to have a side effect to be -useful. For example, the function `Math.max` takes any number of -number values and gives back the greatest. +(((comparación,de números)))(((valor de retorno)))(((función +Math.max)))(((máximo)))Mostrar un cuadro de diálogo o escribir texto +en la pantalla es un _((efecto secundario))_. Muchas funciones son útiles porque +producen valores, y en ese caso, no necesitan tener un efecto secundario para +ser útiles. Por ejemplo, la función `Math.max` toma un número indeterminado de +números y regresa el más grande. [source,javascript] ---- @@ -292,12 +293,12 @@ console.log(Math.max(2, 4)); // → 4 ---- -(((function,application)))(((minimum)))(((Math.min -function)))When a function produces a value, it is said to _return_ -that value. Anything that produces a value is an ((expression)) in -JavaScript, which means function calls can be used within larger -expressions. Here a call to `Math.min`, which is the opposite of -`Math.max`, is used as an input to the plus operator: +(((función,aplicación)))(((minimo)))(((función +Math.min))) Cuando una función produce un valor, se dice que _regresa_ +ese valor. Cualquier cosa que produce un valor es una ((expresión)) en +JavaScript, lo que significa que puede ser usada dentro de expresiones +más grandes. Aquí, una llamada a `Math.min`, que es lo opuesto a +`Math.max`, es usada como entrada de un operador de suma: [source,javascript] ---- @@ -305,29 +306,29 @@ console.log(Math.min(2, 4) + 100); // → 102 ---- -The link:03_functions.html#functions[next chapter] explains how to -write your own functions. +El link:03_functions.html#functions[próximo capítulo] explica como escribir +tus propias funciones. -== prompt and confirm == +== Pedir información y confirmar == -(((dialog box)))(((input)))(((browser)))(((confirm function)))Browser -environments contain other functions besides `alert` for popping up -windows. You can ask the user an OK/Cancel question using -`confirm`. This returns a Boolean: `true` if the user clicks OK and -`false` if the user clicks Cancel. +(((cuadro de diálogo)))(((entrada)))(((navegador)))(((función confirm)))Los +entornos de navegador tienen otras funciones más allá de `alert` para mostrar +ventanas. Puedes preguntar al usuario una cuestión estilo OK/Cancelar usando +`confirm`. Esto regresa un Booleano: `true` si el usuario hace click en OK y +`false` si el usuario presiona en Cancelar. [source,javascript] ---- -confirm("Shall we, then?"); +confirm("¿Entonces, deberíamos?"); ---- image::img/confirm.png[alt="A confirm dialog",width="8cm"] -(((input)))(((prompt function)))(((text input)))The `prompt` function -can be used to ask an “open” question. The first argument is the -question, the second one is the text that the user starts with. A line -of text can be typed into the dialog window, and the function will -return this text as a string. +(((entrada)))(((función prompt)))(((entrada de texto)))La función `prompt` +puede ser usada para hacer una pregunta "abierta". El primer argumento +es la pregunta, el segundo es un texto con el que usuario inicia. Se puede +escribir una línea de texto en el cuadro de diálogo, y la función regresará +este texto como una cadena. [source,javascript] ---- @@ -336,123 +337,115 @@ prompt("Tell me everything you know.", "..."); image::img/prompt.png[alt="An prompt dialog",width="8cm"] -These two functions aren't used much in modern web programming, mostly -because you have no control over the way the resulting windows look, -but they are useful for toy programs and experiments. +Estas dos funciones no son usadas mucho en la programación web moderna, +principalmente porque no tienes control sobre la forma en que las ventanas +resultantes se verán, pero son útiles para programas de prueba y experimentos. -== Control flow == +== Control de flujo == -(((execution order)))(((program)))(((control flow)))When your program -contains more than one ((statement)), the statements are executed, -predictably, from top to bottom. As a basic example, this program has -two statements. The first one asks the user for a number, and the -second, which is executed afterward, shows the ((square)) of that -number. +(((orden de ejecución)))(((programa)))(((control de flujo)))Cuando tu +programa contiene más de una ((sentencia)), las sentencias son ejecutadas (fácil de predecir), de arriba hacia abajo. Como un ejemplo básico, este programa +tiene dos sentencias. La primera le pide un número al usuario, y la +segunda, que se ejecuta después, muestra el ((cuadrado)) de ese número [source,javascript] ---- -var theNumber = Number(prompt("Pick a number", "")); -alert("Your number is the square root of " + - theNumber * theNumber); +var elNumero = Number(prompt("Dame un número", "")); +alert("Tú número es la raíz cuadrada de " + + elNumero * elNumero); ---- -(((number,conversion to)))(((type coercion)))(((Number -function)))(((String function)))(((Boolean -function)))(((Boolean,conversion to)))The function `Number` converts a -value to a number. We need that conversion because the result of -`prompt` is a string value, and we want a number. There are similar -functions called `String` and `Boolean` that convert values to those -types. +(((number,conversión a)))(((conversión de tipos)))(((función +Number)))(((función String)))(((función Boolean)))(((Boolean, +conversión a))) La función `Numero` convierte un valor a un número. +Necesitamos esa conversión porque el resultado de `prompt` es un valor +de cadena de texto (string), y queremos un número. Hay funciones similares +llamadas `String` y `Boolean` que convierten valores a estos tipos. -Here is the rather trivial schematic representation of straight -control flow: +Aquí está la trivial representación esquemática de un flojo de control recto. image::img/controlflow-straight.svg[alt="Trivial control flow",width="4cm"] -== Conditional execution == +== Ejecución Condicional == -(((Boolean)))(((control flow)))Executing statements in straight-line -order isn't the only option we have. An alternative is _((conditional -execution))_, where we choose between two different routes based on a -Boolean value, like this: +(((Booleano)))(((flujo de control)))Ejecutar sentencia en línea recta no es +la íunica opción que tenemos. Una alternativa es la _((ejecución condicional))_, +en dondne escogemos entre dos rutas diferentes basados en un valor Booleano, +como el siguiente: image::img/controlflow-if.svg[alt="Conditional control flow",width="4cm"] -(((syntax)))(((Number function)))(((if keyword)))Conditional execution -is written with the `if` keyword in JavaScript. In the simple case, we -just want some code to be executed if, and only if, a certain -condition holds. For example, in the previous program, we might want -to show the square of the input only if the input is actually a -number. +(((sintaxis)))(((función Number)))(((if, palabra clave)))La ejecución condicional +se escribe con la palabra clave `if` en JavaScript. En el caso sencillo, +queremos que algo de código se ejecute si, y sólo si, cierta condición se cumple. +Por ejemplo, en el programa previo, podríamos querer mostrar el cuadrado de +la entrada sólo si la entrada es un número. [source,javascript] ---- -var theNumber = Number(prompt("Pick a number", "")); -if (!isNaN(theNumber)) - alert("Your number is the square root of " + - theNumber * theNumber); +var elNumero = Number(prompt("Dame un número", "")); +if (!isNaN(elNumero)) + alert("Tu número es la raíz cuadrada de " + + elNumero * elNumero); ---- +Con esta modificación, si le das "queso", no se mostrará ninguna salida. -With this modification, if you enter “cheese”, no output will be shown. - -The keyword `if` executes or skips a statement depending on the value -of a Boolean expression. The deciding expression is written after the -keywords, between ((parentheses)), followed by the statement to execute. +La palabra clave `if` ejecuta o salta una sentencia dependiendo del valor +de una expresión Booleana. La expresión de decisión se escribe después de +la palabra clave, entre ((parántesis)), seguida por una sentencia a ejecutar. -(((isNaN function)))The `isNaN` function is a standard JavaScript -function that returns `true` only if the argument it is given is -`NaN`. The `Number` function happens to return `NaN` when you give it -a string that doesn't represent a valid number. Thus, the condition -translates to “unless `theNumber` is not-a-number, do this”. +(((función isNaN)))La función `isNaN` es una función estándar de JavaScript +que regresa `true` sólo si el argumento que le diste es `NaN`. Resulta que +la función Number regresa `NaN` cuando le das una cadena que no +“a menos que `elNumero` no sea un número, has esto”. -(((else keyword)))You often won't just have code that executes when a -condition holds true, but also code that handles the other case. This -alternate path is represented by the second arrow in the -diagram. The `else` keyword can be used, together with `if`, to create -two separate, alternative execution paths. +(((palabra clave else)))A menudo no sólo tendrás código que se ejecute cuando +una condición sea verdadera, sino también que maneje el otro caso. Este camino +alternativo es representado por la segunda flecha en el diagrama. La palabra +clave `else` puede ser usada, junto con `if`, para crear dos rutas de ejecución +separadas y alternativas. [source,javascript] ---- -var theNumber = Number(prompt("Pick a number", "")); -if (!isNaN(theNumber)) - alert("Your number is the square root of " + - theNumber * theNumber); +var elNumero = Number(prompt("Dame un número", "")); +if (!isNaN(elNumero)) + alert("Tu número es la raíz cuadrada de " + + elNumero * elNumero); else - alert("Hey. Why didn't you give me a number?"); + alert("Hey. ¿Por qué no me diste un número?"); ---- -(((if keyword,chaining)))If we have more than two paths to choose -from, multiple `if`/`else` pairs can be “chained” together. Here's an -example: +(((palabra clave if ,encadenado)))Si tenemos más de dos caminos a escoger, +varios pares de `if`/`else` pueden ser "encadenados". Aquí hay un ejemplo: [source,javascript] ---- -var num = Number(prompt("Pick a number", "0")); +var num = Number(prompt("Dame un número", "0")); if (num < 10) - alert("Small"); + alert("Chico"); else if (num < 100) - alert("Medium"); + alert("Mediano"); else - alert("Large"); + alert("Grande"); ---- -The program will first check whether `num` is less than 10. If it is, -it chooses that branch, shows `"Small"`, and is done. If it isn't, it -takes the `else` branch, which itself contains a second `if`. If the -second condition (`< 100`) holds, that means the number is between 10 -and 100, and `"Medium"` is shown. If it doesn't, the second, and last, -`else` branch is chosen. +El programa primero checará sí `num` es menor que 10. Si lo es, escoge +ese camino, muestra `"Chico"` y termina. Si no lo es, toma el el branch +`else`, que en sí mismo contiene un segundo `if`. Si la segunda condición +(`< 100`) se cumple, significa que el número está entre 10 y 100, y se +muestra `"Mediano"`. Si no lo es, el segundo y último `else` es escogido. -The flow chart for this program looks something like this: +El diagrama de flujo para este programa es algo así: image::img/controlflow-nested-if.svg[alt="Nested if control flow",width="4cm"] -[[loops]] -== while and do loops == +[[bucles]] +== bucles while y do == -(((even number)))Consider a program that prints all even numbers from -0 to 12. One way to write this is as follows: +(((número par)))Piensa en un programa que imprima todos +los números primos del 1 al 12. Una manera de escribirlo +sería como sigue: [source,javascript] ---- @@ -465,422 +458,424 @@ console.log(10); console.log(12); ---- -(((control flow)))That works, but the idea of writing a program is to -make something _less_ work, not more. If we needed all even numbers -less than 1,000, the previous would be unworkable. What we need is a -way to repeat some code. This form of control flow is called a -_((loop))_: +(((control de flujo)))Eso funciona, pero la idea de escribir un programa es +trabajar _menos_, no más. Si necesitamos todos los números menores que +1,000, lo anterior sería imposible de trabajar. Lo que necesitamos es una +forma de repetir algo de código. Esta forma de control de flujo es llamada _((bucle))_: image::img/controlflow-loop.svg[alt="Loop control flow",width="4cm"] -(((syntax)))(((counter variable)))Looping control flow allows us to go -back to some point in the program where we were before and repeat it -with our current program state. If we combine this with a variable -that counts, we can do something like this: +(((sintaxis)))(((variable contador)))El control de flujo por bucles nos +permite regresar a cierto punto en el progrma en el que estuvimos antes +y repetirlo con nuestro estado actual. Si combinamos esto con una variable +que mantenga una cuenta, podemos hacer algo como lo siguiente: [source,javascript] ---- -var number = 0; -while (number <= 12) { - console.log(number); - number = number + 2; +var numero = 0; +while (numero <= 12) { + console.log(numero); + numero = numero + 2; } // → 0 // → 2 // … etcetera ---- -(((while loop)))(((Boolean)))A ((statement)) starting with the -keyword `while` creates a loop. The word `while` is followed by an -((expression)) in ((parentheses)) and then a statement, much like `if`. -The loop executes that statement as long as the expression produces a -value that is `true` when converted to Boolean type. - -(((grouping)))((({} (block))))(((block)))In this loop, we want to both -print the current number and add two to our variable. Whenever we need -to execute multiple ((statement))s inside a loop, we wrap them in -((curly braces)) (`{` and `}`). Braces do for statements what -((parentheses)) do for expressions: they group them together, making -them count as a single statement. A sequence of statements wrapped in -braces is called a _block_. - -(((programming style)))Many JavaScript programmers wrap every single -loop or `if` body in braces. They do this both for the sake of -consistency and to avoid having to add or remove braces when changing -the number of statements in the body later. In this book, I will write -most single-statement bodies without braces, since I value brevity. -You are free to go with whichever style you prefer. - -(((comparison)))(((state)))The variable `number` demonstrates the way -a ((variable)) can track the progress of a program. Every time the -loop repeats, `number` is incremented by `2`. Then, at the beginning -of every repetition, it is compared with the number `12` to decide -whether the program has done all the work it intended to do. - -(((exponentiation)))As an example that actually does something useful, -we can now write a program that calculates and shows the value of -2^10^ (2 to the 10th power). We use two variables: one to keep -track of our result and one to count how often we have multiplied this -result by 2. The loop tests whether the second variable has reached 10 -yet and then updates both variables. +(((bucle while)))(((Booleano)))Una ((sentencia)) que comienza con la palabra +clave `while` crea un bucle. Después de `while` viene una ((expresión)) en +((paréntesis)) y después una sentencia, muy parecido a el `if`. El bucle +ejecuta la sentencia mientras la expresión produzca un valor que sea +`true` cuando se convierta a un tipo Booleano. + +(((agrupamiento)))((({} (bloque))))(((bloque)))En este bucle, queremos +tanto imprimir el número como sumar dos a nuestra variable. Cuando necesitamos +ejecutar múltiples ((sentencia))s dentro de un bucle, lo encerramos +en ((llaves)) (`{` y `}`). Las llaves hacen por las sentencias lo que +los ((paréntesis)) hacen por las expresiones: las agrupan, haciéndolos +valer por una sola sentencia. Una secuencia de sentencias encerradas +en llaves es llamada un _bloque_. + +(((estilo de programación)))Muchos programadores de JavaScript encierran +cada cuerpo de un bucle o `if` en llaves. Lo hacen en nombre de la consistencia +y para evitar tener que añadir o quitar las llaves cuando el número de +sentencias en el cuerpo cambie. En este libro escribiré la mayoría de los +cuerpos de una sola sentencia sin bloques, porque valoro la brevedad. +Tú eres libre de usar el estilo que prefieras. + +(((comparación)))(((estado)))La variable número demuestra la forma en que +una ((variable)) puede dar seguimiento al progreso de un programa. +Cada vez que el bucle se repite, `numero` se incrementa en `2`. Entonces, +al principio de cada repetición. es comparada con el número `12` para decidir +si el programa ha hecho todo el trabajo que tenía que hacer. + +(((exponenciación)))Como un ejemplo que hace realmente algo útil, +podemos escribir un programa que calcula y mustra el valor de 2^10 +(dos a la décima potencia). Usamos dos varianles: una para mantener el +resultado y una para contar cuantas veces hemos multiplicado este +resultado por dos. El bucle verifica si la segunda variable ha llegado +a 10 y entonces actualiza las dos variables. [source,javascript] ---- -var result = 1; -var counter = 0; -while (counter < 10) { - result = result * 2; - counter = counter + 1; +var resultado = 1; +var contador = 0; +while (contador < 10) { + resultado = resultado * 2; + contador = contador + 1; } -console.log(result); +console.log(resultado); // → 1024 ---- -The counter could also start at `1` and check for `<= 10`, but, for -reasons that will become apparent in -link:04_data.html#array_indexing[Chapter 4], it is a good idea to get -used to counting from 0. +El contador pudo también empezar en `1` y verificar que `<=10`, pero, +por razones que se aclararán en el +link:04_data.html#array_indexing[Capítulo 4], es una buena idea acostumbrarse +a contar desde 0. -(((loop body)))(((do loop)))(((control flow)))The `do` loop is a -control structure similar to the `while` loop. It differs only on one -point: a `do` loop always executes its body at least once, and it -starts testing whether it should stop only after that first execution. -To reflect this, the test appears after the body of the loop: +(((cuerpo del bucle)))(((bucle do)))(((control de flujo)))El bucle `do` es una +estructura de control similar al bucle `while`. Se diferencia en sólo +un punto: un bucle `do` siempre ejecuta su cuerpo por lo menos una vez y +empieza a verificar si debería para sólo después de la primera ejecución. +Para reflejar esto, la condición aprece después del cuerpo del bucle: [source,javascript] ---- do { - var name = prompt("Who are you?"); -} while (!name); -console.log(name); ----- - -(((Boolean,conversion to)))(((! operator)))This program will -force you to enter a name. It will ask again and again until it gets -something that is not an empty string. Applying the `!` operator will -convert a value to Boolean type before negating it, and all strings -except `""` convert to `true`. - -== Indenting Code == - -(((block)))(((code structure)))(((whitespace)))(((programming -style)))You've probably noticed the spaces I put in front of some -statements. In JavaScript, these are not required—the computer will -accept the program just fine without them. In fact, even the ((line)) -breaks in programs are optional. You could write a program as a single -long line if you felt like it. The role of the ((indentation)) inside -blocks is to make the structure of the code stand out. In complex -code, where new blocks are opened inside other blocks, it can become -hard to see where one block ends and another begins. With proper -indentation, the visual shape of a program corresponds to the shape of -the blocks inside it. I like to use two spaces for every open block, -but tastes differ—some people use four spaces, and some people use -((tab character))s. - -== for loops == - -(((syntax)))(((while loop)))(((counter variable)))Many loops follow -the pattern seen in the previous `while` examples. First, a “counter” -variable is created to track the progress of the loop. Then comes a -`while` loop, whose test expression usually checks whether the counter -has reached some boundary yet. At the end of the loop body, the -counter is updated to track progress. - -(((for loop)))(((loop)))Because this pattern is so common, JavaScript and -similar languages provide a slightly shorter and more comprehensive -form, the `for` loop. + var tuNombre = prompt("¿Quién eres?"); +} while (!tuNombre); +console.log(tuNombre); +---- + +(((Booleano,conversión a)))(((operador !)))Este programa te obligará a +introducir un nombre. Preguntará una y otra vez hasta que obtenga algo que +no sea una cadena vacía. Aplicar el operador `!` convierte un valor a Booleano +negándolo y todas las cadenas excepto `""` se convierten a `true`. Esto significa +qie el bucle continúa corriendo hasta que des un nombre que no sea una cadena vacía. + +== Indentando código == + +(((bloque)))(((estructura del código)))(((espacio en blanco)))(((estilo de +programción))) Probablemente has notado los espacios que pongo en frente +de algunas sentencias. En JavaScript, no son requeridos, la computadora +aceptaré el programa bien sin ellos. De hecho, incluso los saltos de ((línea)) +en los programas son opcionales. Puedes escribir un programa en una sola línea +si así lo prefieres. El rol de la ((indentación)) dentro de los +bloques es hacer notar la estructura del código. En código complejo, +en dónde nuevos bloques son abiertos dentro de otros bloques, puede ser difícil +de ver en dónde termina uno y empieza otro. Con la indentación correcta, +la forma visual del programa se corresponde con la forma de los bloques dentro +de él. A mí me gusta usar dos espacios por cada bloque abierto, pero los gustos +varían; algunas personas usan cuatro espacios, y algunas +otras usan el ((carácter tab)). + +== Bucles for == + +(((sintaxis)))(((bucle while)))(((variable contador)))Muchos bucles siguen el +patrón de los ejemplos previos del `while`. Primero, una variable “contador” +es creada para dar seguimiento al progreso del bucle. Entonces viene el +bucle `while`, cuya expresión condicional normamelte verifica si el +contador ha alcanzafo cierto límite. El final del cuerpo del bucle, el +contador es actualizado para dar seguimiento al progreso. + +(((bucle for)))(((bucle)))Debido a que este patrón es tan común, JavaScript +y otros lenguajes similares proveen una versión un poco más corta y más +completa, el bucle `for`. + [source,javascript] ---- -for (var number = 0; number <= 12; number = number + 2) - console.log(number); +for (var numero = 0; numero <= 12; numero = numero + 2) + console.log(numero); // → 0 // → 2 -// … etcetera +// … etc. ---- -(((control flow)))(((state)))This program is exactly equivalent to the -link:02_program_structure.html#loops[earlier] even-number-printing -example. The only change is that all the ((statement))s that are -related to the “state” of the loop are now grouped together. +(((control de flujo)))(((estado)))Este programa es exactamente equivalente +a el link:02_program_structure.html#loops[ejemplo previo] de impresión +de números pares. El único cambio es que todas las ((sentencia))s que están +relacionadas con el "estado" del bucle están agrupadas. -The ((parentheses)) after a `for` keyword must contain two -((semicolon))s. The part before the first semicolon _initializes_ the -loop, usually by defining a ((variable)). The second part is the -((expression)) that _checks_ whether the loop must continue. The final -part _updates_ the state of the loop after every iteration. In most -cases, this is shorter and clearer than a `while` construct. +Los ((paréntesis)) después de una palabra clave `for` tienen que contener +dos ((punto y coma)). La parte que está antes del primer punto y coma +_inicializa_ el bucle, normalmente al definir una ((variable)). La segunda parte es la ((expresión)) que verifica si el bucle tiene que continuar. +La parte final _actualiza_ el estado del bucle antes de cada iteración. En +la mayoría de los casos, esto es más corto y claro que una construcción con +`while`. -(((exponentiation)))Here is the code that computes 2^10^, using `for` -instead of `while`: +(((exponenciación)))Aquí está un código que calcula 2^10^, usando el `for` +en vez del `while`. [source,javascript] ---- -var result = 1; -for (var counter = 0; counter < 10; counter = counter + 1) - result = result * 2; -console.log(result); +var resultado = 1; +for (var contador = 0; contador < 10; contador = contador + 1) + resultado = resultado * 2; +console.log(resultado); // → 1024 ---- -(((programming style)))(((indentation)))Note that even though no block -is opened with a `{`, the statement in the loop is still indented two -spaces to make it clear that it “belongs” to the line before it. +(((estilo de programación)))(((indentación)))Nota que incluso aunque no se +abrió ningún bloque con un `{`, la sentencia del bucle está indentada dos +espacios para dejar claro que "pertenece" al la línea que está antes de +ella. -== Breaking Out of a Loop == +== Forzando la salida de un bucle == -(((loop,termination of)))(((break keyword)))Having the loop's -condition produce `false` is not the only way a loop can finish. There -is a special statement called `break` that has the effect of -immediately jumping out of the enclosing loop. +(((bucle, terminación de)))(((palabra clave break)))Hacer que la condición del bucle produzca `false` no es la única forma de que un bucle termine. +Existe una una sentencia especial llamada `break` que tiene el +efecto de salir inmediatamente del bucle que la esté encerrando. -This program illustrates the `break` statement. It finds the first number -that is both greater than or equal to 20 and divisible by 7. +El siguiente programa ilustra la sentencia `break`. Encuentra el primer +número que es más grande o igual que 20 y divisible por 7. [source,javascript] ---- -for (var current = 20; ; current++) { - if (current % 7 == 0) +for (var actual = 20; ; actual++) { + if (actual % 7 == 0) break; } -console.log(current); +console.log(actual); // → 21 ---- -(((remainder operator)))(((% operator)))Using the remainder -(`%`) operator is an easy way to test whether a number is divisible by -another number. If it is, the remainder of their division is zero. +(((operador sobrante)))(((operador %)))Usar el operador de sobrante o +módulo (`%`) es una forma fácil de probar si un número es divisible por +otro. Si lo es, el sobrante de la división es cero. -(((for loop)))The `for` construct in the example does not have a part -that checks for the end of the loop. This means that the loop will -never stop unless the `break` statement inside is executed. +(((bucle for)))La construcción `for` en este ejemplo no tiene la parte +que verifica si el bucle debe terminar. Esto significa que el loop nunca +terminará hasta que la sentencia `break` que está adentro sea ejecutada. -If you were to leave out that `break` statement or accidentally write -a condition that always produces `true`, your program would get stuck -in an _((infinite loop))_. A program stuck in an infinite loop will -never finish running, which is usually a bad thing. +Si dejaras afuera esa sentencia `break` o accidentalmente escribieras una +condición que siempre produzca `true`, tu programa se quedaría atorado en +un _((bucle infinito))_. Un programa que se queda en un bucle infinito +nunca terminará de correr, y eso usualmente es malo. ifdef::interactive_target[] -If you create an infinite loop in one of the examples on these pages, -you'll usually be asked whether you want to stop the script after a -few seconds. If that fails, you will have to close the tab that you're -working in, or on some browsers close your whole browser, in order to -recover. +Si creas un bucle infinito en uno de los ejemplos de estas páginas, +usualmente se te preguntará si quieres detener el script después de unos +cuantos segundos. Si eso falla, tendrás que cerrar la pestaña en la que +estás trabajando, o, en otros nevagadores, cerrar el navegador entero para +recuperarte. endif::interactive_target[] -(((continue keyword)))The `continue` keyword is similar to `break`, in -that it influences the progress of a loop. When `continue` is -encountered in a loop body, control jumps out of the body and -continues with the loop's next iteration. +(((palabra clave continue)))La palabra clave `continue` es similar a +`break` en que influencia el progreso del bucle. Cuando se encuentra +`continue` en el cuerpo de un bucle, el control sale del curpo del +bucle inmediatamente y continúa en la próxima iteración del bucle. -== Updating variables succinctly == +== Actualizando variables sucintamente == -(((assignment)))(((+= operator)))(((-= operator)))(((/= -operator)))(((*= operator)))(((state)))(((side effect)))Especially -when looping, a program often needs to “update” a variable to hold a -value based on that variable's previous value. +(((asiganción)))(((operador +=)))(((operador -=)))(((operador +/=)))(((operador \*=)))(((estado)))(((efecto secundario)))Especialmente +cuando estamos en un bucle, un programa necesita "actualizar" una variable +para mantener un valor basado en el valor previo de esa variable. // test: no [source,javascript] ---- -counter = counter + 1; +contador = contador + 1; ---- -JavaScript provides a shortcut for this: +JavaScript nos da un atajo para esto: // test: no [source,javascript] ---- -counter += 1; +contador += 1; ---- -Similar shortcuts work for many other operators, such as `result *= 2` to -double `result` or `counter -= 1` to count downward. +Atajos similares funcionan igual para muchos otros operadores, como +`resultado *= 2` para duplicar `resultado` o `counter -= 1` para restar uno. -This allows us to shorten our counting example a little more. +Esto nos permite acortar nuestro ejemplo de la cuenta un poco más. [source,javascript] ---- -for (var number = 0; number <= 12; number += 2) - console.log(number); +for (var numero = 0; numero <= 12; numero += 2) + console.log(numero); ---- -(((++ operator)))(((-- operator)))For `counter += 1` and `counter -= -1`, there are even shorter equivalents: `counter++` and `counter--`. +(((operador ++)))(((operador --)))Para `contador += 1` y `contador -= 1`, +hay incluso equivalentes más cortos: `contador+=` y `contador--`. -== Dispatching on a value with switch == +== Despachando sobre un valor con switch == -(((syntax)))(((conditional execution)))(((dispatching)))(((if -keyword,chaining)))It is common for code to look like this: +(((sintaxis)))(((ejecución condicional)))(((despachando)))(((palabra clave if, +encadenamiento)))Es común ver código así: // test: no [source,javascript] ---- -if (variable == "value1") action1(); -else if (variable == "value2") action2(); -else if (variable == "value3") action3(); -else defaultAction(); +if (variable == "valor1") accion1(); +else if (variable == "valor2") accion2(); +else if (variable == "valor3") accion3(); +else accionDefault(); ---- -(((colon character)))(((switch keyword)))There is a construct called -`switch` that is intended to solve such a “dispatch” in a more direct -way. Unfortunately, the syntax JavaScript uses for this (which it -inherited from the C/Java line of programming languages) is somewhat -awkward—a chain of `if` statements often looks better. Here is an -example: +(((caracter punto y coma)))(((palabra clave switch)))Existe una estructura +llamada `switch` que está hecha para resolver este "despachado" de un modo +más directo. Desafortunadamente, la sintaxis que JavaScript usa para +esto (que es heredada de la línea de lenguajes de programación de C o Java) +es un poco incómoda; una cadena de sentencias `if` a menudo luce mejor. +Aquí hay un ejemplo: [source,javascript] ---- -switch (prompt("What is the weather like?")) { - case "rainy": - console.log("Remember to bring an umbrella."); +switch (prompt("¿Cómo está el clima?")) { + case "lluvioso": + console.log("Recuerda llevar un paraguas."); break; - case "sunny": - console.log("Dress lightly."); - case "cloudy": - console.log("Go outside."); + case "soleado": + console.log("Viste ligero."); + case "nublado": + console.log("Sal a la calle."); break; default: - console.log("Unknown weather type!"); + console.log("Tipo de Clima desconocido."); break; } ---- -(((fallthrough)))(((comparison)))(((break keyword)))(((case -keyword)))(((default keyword)))You may put any number of `case` labels -inside the block opened by `switch`. The program will jump to the -label that corresponds to the value that `switch` was given or to -`default` if no matching value is found. It starts executing -statements there, even if they're under another label, until it -reaches a `break` statement. In some cases, such as the `"sunny"` case -in the example, this can be used to share some code between cases (it -recommends going outside for both sunny and cloudy weather). But -beware: it is easy to forget such a `break`, which will cause the -program to execute code you do not want executed. - -== Capitalization == - -(((capitalization)))(((variable,naming)))(((whitespace)))Variable -names may not contain spaces, yet it is often helpful to use multiple -words to clearly describe what the variable represents. These are -pretty much your choices for writing a variable name with several -words in it: - ----- -fuzzylittleturtle -fuzzy_little_turtle -FuzzyLittleTurtle -fuzzyLittleTurtle ----- - -(((camel case)))(((programming style)))(((underscore character)))The -first style can be hard to read. Personally, I like the look of the -underscores, though that style is a little painful to type. The -((standard)) JavaScript functions, and most JavaScript programmers, -follow the bottom style—they capitalize every word except the first. -It is not hard to get used to little things like that, and code with -mixed naming styles can be jarring to read, so we will just follow -this ((convention)). - -(((Number function)))(((constructor)))In a few cases, such as the -`Number` function, the first letter of a variable is also capitalized. -This was done to mark this function as a constructor. What a -constructor is will become clear in -link:06_object.html#constructors[Chapter 6]. For now, the important -thing is not to be bothered by this apparent lack of ((consistency)). - -== Comments == - -(((readability)))Often, raw code does not convey all the information -you want a program to convey to human readers, or it conveys it in -such a cryptic way that people might not understand it. At other -times, you might just feel poetic or want to include some thoughts as -part of your program. This is what _((comment))s_ are for. - -(((slash character)))(((line comment)))A comment is a piece of text -that is part of a program but is completely ignored by the computer. -JavaScript has two ways of writing comments. To write a single-line -comment, you can use two slash characters (`//`) and then the comment -text after it. +(((fallthrough)))(((comparación)))(((palabra clave break)))(((palabra calve +case)))(((palabra clave default))) Puedes poner cualquier cantidad +de etiquetas `case` dentro del bloque `switch` abierto. El programa +saltará a la etiqueta que corresponda al valor que se le dio al +`switch` o a `default` si no se encuentra valor que corresponda. +Se empiezan a ejecutar las sentencias desde ahí, incluso si están +bajo otra etiqueta, hasta que se llegue a una sentencia `breal`. +En algunos casos, como en el caso de `"soleado"` en el ejemplo, esto +puede ser usado para compartir código entre casos (recomienda +salir a la calle tanto para clima soleado como para nublado). Pero +cuidado: es fácil olvidar el `break`, lo cuál causará que el programa +ejecute código que no quieres que se ejecute. + +== Capitalización == + +(((capitalización)))(((variable, nombrado)))(((espacio en blanco)))Los +nombres de variable no pueden contener espacios, pero aún así es útil +ocupar varias palabras para describir claramente lo que esa variable +representa. Estas son tus elecciones para escribir un nombre +de variable con varias palabras: + +---- +toortuguitadifusa +tortuguita_difusa +TortuguitaDifusa +tortuguitaDifusa +---- + +(((camel case)))(((estilo de programación)))(((carácter guión bajo)))El +primer estilo puede ser difícil de leer. Personalmente, me gusta como +luce con los guiones bajos, aunque es un poco difícil de escribir. Las +funciones ((estándar)) de JavaScript, y la mayoría de los programadores +de JavaScript, siguen el último estilo; capitalizan cada palabra excepto la +primera. No es difícil acostumbrarse a pequeñas cosas como esas y código +con estilos de nombrado mezclados puede ser desagradable de leer, +así que simplemente seguiremos esta ((convención)). + +(((función Number)))(((constructor)))En algunos casos, como en el +de la función `Number`, la primera letra de una variable también es +mayúscula. Esto fue hecho para marcar la función como un constructor. +Lo que es un constructor, quedará claro en el +link:06_object.html#constructors[Capítulo 6]. Por ahora, lo importante +es no preocuparse por esta aparente falta de ((consistencia)). + +== Comentarios == + +(((legibilidad)))A menudo, el código por sí mismo no transmite toda la +información que quieres que un programa transmita para los lectores +humanos, o la transmite de un modo tan críptico que las personas +podrían no entenderlo. En otras ocasiones, simplemente puedieras +sentirte poético o quisieras incluir algunos pensamientos como parte +del programa. Para eso son los _((comentario))s_. + +(((carácter diagonal)))(((comentario de línea)))Un comentario es una +pieza de texto que es parte del programa pero es completamente ignorado +por la computadora. JavaScript tiene dos formas para escribir comentarios. +Para escribir un comentario de una línea, puedes usar dos diagonales ('//') +con el texto después. // test: no [source,javascript] ---- -var accountBalance = calculateBalance(account); -// It's a green hollow where a river sings -accountBalance.adjust(); -// Madly catching white tatters in the grass. -var report = new Report(); -// Where the sun on the proud mountain rings: -addToReport(accountBalance, report); -// It's a little valley, foaming like light in a glass. +var balandeDeCuenta = calcularBalance(cuenta); +// Es en un claro de bosque donde canta un río. +balandeDeCuenta.ajustar(); +// Cuelgan enloquecidamente de la hierbas harapos +var reporte = new Reporte(); +// De plata; donde el sol de la orgullosa montaña +agregaAReporte(balandeDeCuenta, reporte); +// Luce: Es un pequeño valle espumoso de luz. ---- -(((block comment)))A `//` comment goes only to the end of the line. A -section of text between `/*` and `*/` will be ignored, regardless of -whether it contains line breaks. This is often useful for adding -blocks of information about a file or a chunk of program. +(((comentario de bloque)))Un `//` sólo es válido hasta el fin de la línea. +Una sección de texto entre `/*` y '*/' será ignorada, sin importar si +contiene saltos de línea. Esto es útil a menudo para añadir bloques de +información acerca de un archivo o un pedazo de un programa. [source,javascript] ---- /* - I first found this number scrawled on the back of one of - my notebooks a few years ago. Since then, it has often - dropped by, showing up in phone numbers and the serial - numbers of products that I've bought. It obviously likes - me, so I've decided to keep it. + Primero, encontré este número garabateado en la parte trasera de + una de mis libretas hace unos cuantos años. Desde entonces, + a menudo ha aparecido de la nada, apareciendo en números de + teléfono y números de serie de productos que he comprado. + Obviamente le gusto, así que decidí conservarlo. */ -var myNumber = 11213; +var miNumero = 11213; ---- -== Summary == +== Sumario == -You now know that a program is built out of statements, which -themselves sometimes contain more statements. Statements tend to -contain expressions, which themselves can be built out of smaller -expressions. +Ya sabes que un programa está construido de sentencias, que +a su vez pueden contener más sentencias algunas veces. Las +sentencias normalmente contienen expresiones, que a su vez pueden +contener expresiones más pequeñas. -Putting statements after one another gives you a program that is -executed from top to bottom. You can introduce disturbances in the -flow of control by using conditional (`if`, `else`, and `switch`) and -looping (`while`, `do`, and `for`) statements. +Colocar una sentencia tras otras te da un programa que es ejecutado +de arriba hacia abajo. Puedes introducir disturbios en el flujo de +control usando sentencias condicionales (`if`, `else`, and `switch`) y +de bucle (`while`, `do`, and `for`). -Variables can be used to file pieces of data under a name, and they -are useful for tracking state in your program. The environment is the -set of variables that are defined. JavaScript systems -always put a number of useful standard variables into your -environment. +Las variables pueden ser usadas para guardar piezas de información bajo un +nombre, y son útiles para llevar registro del estado del programa. +El entorno es el conjunto de variables que están definidas. Los sistemas +de JavaScript siempre colocan varias variables estándar útiles en +tu entorno. -Functions are special values that encapsulate a piece of program. You -can invoke them by writing `functionName(argument1, argument2)`. Such -a function call is an expression, and may produce a value. +Las funciones son valores especiales que encapsulan un pedazo del programa. +Puedes invocar una escribiendo `nombreDeLaFuncion(argumento1, argumento2)`. +Esta llamada a la función es una expresión, y podría producir un valor. -== Exercises == +== Ejercicios == -(((exercises)))If you are unsure how to try your solutions to -exercises, refer to the link:00_intro.html#intro[introduction]. +(((ejercicios)))Si no estás seguro de cómo probar tus soluciones a los +ejercicios, visita la link:00_intro.html#intro[introducción] -Each exercise starts with a problem description. Read that and try to -solve the exercise. If you run into problems, consider reading the -hints (!interactive after the exercise!)(!book at the link:hints.html#hints[end of the book]!). -Full solutions to the exercises are not included in this -book, but you can find them online at +Cada ejercicio empieza con una descripción del problema. Léela e intenta +resolver el ejercicio. Si tienes problemas, considera leer las pistas +(!interactive después del ejercicio!)(!book al link:hints.html#hints[final del libro]!). +Las soluciones completas a los ejercicios no están incluidas en este +libro, pero puedes encontrarlas en línea en http://eloquentjavascript.net/code[_eloquentjavascript.net/code_]. -If you want to learn something from the exercises, I recommend looking -at the solutions only after you've solved the exercise, or at least -after you've attacked it long and hard enough to have a slight -headache. +Si quieres aprender a partir de los ejercicios, recomiendo mirar las soluciones +sólo después de que hayas resuelto el ejercicio, o al menos lo hayas +atacado con el tiempo y esfuerzo suficientes para tener un pequeño dolor +de cabeza. -=== Looping a triangle === +=== Iterando un triángulo === -(((triangle (exercise))))Write a ((loop)) that makes seven calls to -`console.log` to output the following triangle: +(((triángulo (ejercicio))))Escribe un ((bucle)) que haga siete +llamadas a `console.log` para producir el siguiente triángulo: ---- # @@ -892,8 +887,8 @@ headache. ####### ---- -It may be useful to know that you can find the length of a string by -writing `.length` after it. +Puede ser útil saber que puedes encontrar la longitud de una cadena +de texto escribiendo `.length` después de ella. [source,javascript] ---- @@ -904,82 +899,87 @@ console.log(abc.length); ifdef::interactive_target[] -Most exercises contain a piece of code that you can modify to solve -the exercise. Remember that you can click code blocks to edit them. +La mayoría de los ejercicios contienen una porción de código +que puedes modificar para resolver el ejercicio. Recuerda que puedes hacer +click en los bloques de código para editarlos. [source,javascript] ---- -// Your code here. +// Tu código aquí: ---- endif::interactive_target[] !!hint!! -(((triangle (exercise))))You can start with a program that simply -prints out the numbers 1 to 7, which you can derive by making a few -modifications to the -link:02_program_structure.html#loops[even number printing example] -given earlier in the chapter, where the `for` loop was introduced. +(((triángulo (exercise))))Puedes empezar con un programa que +simplemente imprima los números 1 a 7, el cuál puede derivarse +de hacer unas cuantas modificaciones al +link:02_program_structure.html#loops[ejemplo de impresión de +los números pares] dado antes en este capítulo, +en dónde se introdujo el bucle `for`. -Now consider the equivalence between numbers and strings of hash -characters. You can go from 1 to 2 by adding 1 (`+= 1`). You can go -from `"#"` to `"##"` by adding a character (`+= "#"`). Thus, your -solution can closely follow the number-printing program. +Ahora considera la equivalencia entre números y cadenas de símbolos +de numeral. Puedes ir de uno a dos añadiendo uno (`+=1`). Puedes +ir de `"#"` a `"##"` añadiendo un carácter (`+= "#"`). Así, tu solución +puede seguir de cerca el programa de impresión de números. !!hint!! === FizzBuzz === -(((FizzBuzz (exercise))))(((loop)))(((conditional execution)))Write a -program that uses `console.log` to print all the numbers from 1 to -100, with two exceptions. For numbers divisible by 3, print `"Fizz"` -instead of the number, and for numbers divisible by 5 (and not 3), -print `"Buzz"` instead. +(((FizzBuzz (ejercicio))))(((bucle)))(((ejecución condicional)))Escribe +un programa que use `console.log` para imprimir todos los números +del 1 al 100, con dos excepciones. Para números divisibles por 3, +imprime `"Fizz"` en vez del número y para números divisibles por 5 +(pero no por 3), imprime `"Buzz"`. -When you have that working, modify your program to print `"FizzBuzz"`, -for numbers that are divisible by both 3 and 5 (and still print -`"Fizz"` or `"Buzz"` for numbers divisible by only one of those). +Cuando tengas eso funcionando, modifica tu programa para imprimir +`"FizzBuzz"`, para números que sean divisibles tanto por 3 como por 5 +(y que siga imprimiendo `"Fizz"` o `"Buzz"` para números divisibles por +sólo uno de ellos). -(This is actually an ((interview question)) that has been claimed to -weed out a significant percentage of programmer candidates. So if you -solved it, you're now allowed to feel good about yourself.) +(Esta es en realidad una ((pregunta de entrevista)) de la que se dice +que elimina a un porcentaje significativo de programadores candidatos. +Así que si lo resolviste, puedes sentirte bien contigo mismo.) ifdef::interactive_target[] + [source,javascript] ---- -// Your code here. +// Tu código aquí: ---- + endif::interactive_target[] !!hint!! -(((FizzBuzz (exercise))))(((remainder operator)))(((% operator)))Going -over the numbers is clearly a looping job, and selecting what to print -is a matter of conditional execution. Remember the trick of using the -remainder (`%`) operator for checking whether a number is divisible by -another number (has a remainder of zero). +(((FizzBuzz (ejercicio))))(((operador sobrante)))(((operador %)))Recorrer +los números es claramente un trabajo para un bucle y seleccionar +qué imprimir es asunto de ejecución condicional. Recuerda el truco +de usar el operador sobrante (`%`) para verificar si un número es divisible +por otro (tiene un sobrante de cero). -In the first version, there are three possible outcomes for every -number, so you'll have to create an `if`/`else if`/`else` chain. +En la primera versión, hay tres posibles salidas para cada número, +así que tendrás que crear una cadena de `if`/`else if`/`else`. -(((|| operator)))(((if keyword,chaining)))The second version of the -program has a straightforward solution and a clever one. The simple -way is to add another “branch” to precisely test the given condition. -For the clever method, build up a string containing the word or words -to output, and print either this word or the number if there is no -word, potentially by making elegant use of the `||` operator. +(((operador ||)))(((palabra clave if keyword,encadenado)))La segunda versión +del programa tiene una solución obvia y una inteligente. El camino simple +es añadir otra "rama" para probar la condición dada. Para el método +inteligente, construye una cadena que contenga la palabra o las palabras +que se van a devolver, e imprime esta palabra o el número si no hay palabra, +probablemente haciendo un uso elegante del operador `||`. !!hint!! -=== Chess board === +=== Tablero de Ajedrez === -(((chess board (exercise))))(((loop)))(((nesting,of loops)))(((newline -character)))Write a program that creates a string that represents an -8×8 grid, using newline characters to separate lines. At each position -of the grid there is either a space or a “#” character. The characters -should form a chess board. +(((tablero de ajedrez (exercise))))(((bucle)))(((anidado,de bucles)))(((caracter +de nueva línea)))Escribe un programa que cree un cadena de texto que +represente una cuadrícula de 8x8, usando el salto de línea como separador. +En cada posición de la cuadrícula está o un espacio o un carácter "#". +Los caracteres deberían formar un tablero de ajedrez. -Passing this string to `console.log` should show something like this: +Pasar esta cadena a `console.log` debería mostrar algo como esto: ---- # # # # @@ -992,40 +992,43 @@ Passing this string to `console.log` should show something like this: # # # # ---- -When you have a program that generates this pattern, define a -((variable)) `size = 8` and change the program so that it works for -any `size`, outputting a grid of the given width and height. +Cuando tengas un programa que genere este patrón, defina +una ((variable)) `tamano = 8` y cambia el programa de tal manera +que trabaje para cualquier `tamano`, produciendo una cuadrícula +del ancho y alto dado. ifdef::interactive_target[] + [source,javascript] ---- -// Your code here. +// Tu código aquí: ---- endif::interactive_target[] !!hint!! -(((chess board (exercise))))The string can be built by starting with -an empty one (`""`) and repeatedly adding characters. A newline -character is written `"\n"`. - -Use `console.log` to inspect the output of your program. - -(((nesting,of loops)))To work with two ((dimensions)), you will need a -((loop)) inside of a loop. Put ((curly braces)) around the bodies of -both loops to make it easy to see where they start and end. Try to -properly indent these bodies. The order of the loops must follow the -order in which we build up the string (line by line, left to right, -top to bottom). So the outer loop handles the lines and the inner loop -handles the characters on a line. - -(((counter variable)))(((remainder operator)))(((% operator)))You'll -need two variables to track your progress. To know whether to put a -space or a hash sign at a given position, you could test whether the -sum of the two counters is even (`% 2`). - -Terminating a line by adding a newline character happens after the -line has been built up, so do this after the inner loop but inside of -the outer loop. +(((tablero de ajedrez (ejercicio))))La cadena puede ser construida +empezando con una vacía (`""`) y agregando caracteres repetidamente. +Un carácter de nueva línea se escribe `"\n"`. + +Usa `console.log` para inspeccionar la salida de tu programa. + +(((anidado,de bucles)))Para trabajar con dos ((dimensiones)), necesitarás +un ((bucle)) adentro de un bucle. Coloca ((llaves)) alrededor de los +cuerpos de los dos bucles para hacer fácil ver dónde empiezan y dónde +terminan. Intenta indentar propieamente los cuerpos. El orden de los +bucles debe seguir el orden en el que construimos la cadena (línea por +línea, de izquierda a derecha, de arriba hacia abajo). Así que el bucle +de afuera maneja la línea y el bucle interno maneja los caracteres en +una línea. + +(((variable contador)))(((operador sobrante)))(((operador %)))Necesitarás +dos variables para dar seguimiento al progreso. Para saber si debes poner +un espacio o un símbolo de número en una posición dada, puedes probar si +la suma de los contadores es par (`%2`) + +Terminar una línea al añadir un carácter de nueva línea sucede después de +que la línea ha sido construida, así que haz esto después del bucle interno +pero dentro del bucle externo. !!hint!! diff --git a/03_functions.txt b/03_functions.txt index 5db87b6a1..3604a69bd 100644 --- a/03_functions.txt +++ b/03_functions.txt @@ -7,8 +7,8 @@ [chapterquote="true"] [quote, Donald Knuth] ____ -La gente piensa que las ciencias de la computación son el -arte de los genios pero la realidad es lo contrario, es sólo un +La gente piensa que las ciencias de la computación son las +artes de los genios pero la realidad es lo contrario, es sólo un montón de gente haciendo cosas que se construyen sobre otras, como una pared de piedras muy pequeñas. ____ @@ -167,7 +167,7 @@ funciones dentro de ella: [source,javascript] ---- -var paisaje = function() { +var landscape = function() { var resultado = ""; var meseta = function(tamano) { for (var cuenta = 0; cuenta < size; cuenta++) @@ -404,7 +404,7 @@ acerca del número de argumentos que le pasas a una función. Sí le pasas demas loa argumentos extra son ignorados. Si le pasas muy pocos, los parámetros quie faltan simplemente son asignados a `undefined`. -El lado malo de esto es que es posbible/probable, casi seguro que le pasarás +El lado malo de esto es que es posible, probable a menudo, que le pasarás accidentalmente un número incorrecto de argumentos a las funciones y nadie te avisará. diff --git a/04_data.txt b/04_data.txt index 51f234625..16ed755ba 100644 --- a/04_data.txt +++ b/04_data.txt @@ -9,16 +9,16 @@ [chapterquote="true"] [quote, Charles Babbage, Passages from the Life of a Philosopher (1864)] ____ -En dos ocasiones me preguntaron - “Disculpe, Sr. Babbage, si pongo +En dos ocasiones me han preguntado “Disculpe, Sr. Babbage, si introduce los números incorrectos en la máquina, ¿van a salir las respuestas correctas?” [...] No puedo terminar de comprender el tipo de confusión de ideas que podrían provocar esta pregunta. ____ -(((Babbage+++,+++ Charles)))(((object)))(((data structure)))Números, Booleanos +(((Babbage+++,+++ Charles)))(((objeto)))(((estructura de datos)))Números, Booleanos y cadenas son los ladrillos de los que están hechas las estructuras de ((datos)). Pero no podrás construir mucha casa de un solo ladrillo. Los _objetos_ nos -permiten agrupar valores-incluyendo otros objetos-permitiéndonos construir +permiten agrupar valores, incluyendo otros objetos, permitiéndonos construir estructuras más complejas. Los programas que hemos construido hasta ahora han sido seriamente limitados @@ -37,100 +37,100 @@ ifdef::book_target[] (((sandbox)))El sandbox de programación en línea para el libro (http://eloquentjavascript.net/code[_eloquentjavascript.net/code_]) proporciona una manera de correr el código en el contexto de un capítulo en -espacífico. Si decides trabajar en los ejemplos en otro entorno, asegúrate de +específico. Si decides trabajar en los ejemplos en otro entorno, asegúrate de descargar primero el código completo de este capítulo desde la página del sandbox. endif::book_target[] -== La ardillalobo == +== El hombre ardilla == -(((weresquirrel example)))(((lycanthropy)))De vez en cuando, comúnmente +(((hombre ardilla, ejemplo)))(((licántropo)))De vez en cuando, comúnmente entre las ocho y las diez de la noche, ((Jacques)) se transforma en un pequeño y peludo roedor con una frondosa cola. Por un lado, Jacques esta bastante contento de no tener la clásica licantropía. Convertirse en una ardilla suele causar menos problemas que convertirse en un lobo. En vez de tener que preocuparse por comerse accidentalmente a un vecino -(_eso_ sería extraño), le preocupa el ser deborado por el gato del vecino. -Después de un par de ocasiones donde se despertó, desnudo y desorientado, en una -apenas delgada rama en la cima de un roble, se ha asegurado de cerrar puertas y -ventanas de su cuarto por las noches y ponear algunas nueces en el suelo para -mantenerse ocupado. +(_eso_ sería penoso), le preocupa el ser deborado por el gato del vecino. +Después de un par de ocasiones donde se despertó, en una +delgada rama en la cima de un roble, desnudo y desorientado, se ha asegurado +de cerrar puertas y ventanas de su cuarto por las noches y poner algunas +bellotas en el suelo para mantenerse ocupado. image::img/weresquirrel.png[alt="The weresquirrel"] Eso resuelve los problemas del gato y el roble. Pero Jacques aún sufre de su -enfermedad. Los momentos irregular en que se presenta la transformación le hacen +enfermedad. Las ocurrencias irregulares de la transformación le hacen sospechar que pudieran ser detonadas por algo. Por algún tiempo, creyó que sucedía sólo en los dias que había tocado árboles. Así que dejó de tocar árboles de manera definitiva e incluso evitó acercarse a ellos. Pero el problema presistió. -(((journal)))Cambiando a una perspectiva un poco más científica, Jacques planea -empezar un registro diario de todo lo que hizo ese día y si tuvo o no una +(((diario)))Cambiando a una perspectiva más científica, Jacques intenta +empezar un registro diario de todo lo que hizo ese día y si tuvo una transformación. Con estos datos espera limitar las condiciones que disparan las transformaciones. -La primer cosa que hace es diseñar una estructura de datos para almacenar esta +Lo primero que hace es diseñar una estructura de datos para almacenar esta información. == Conjuntos de datos == -(((data structure)))Para trabajar con un pedazo de datos digitales, primero +(((estructuras de datos)))Para trabajar con un pedazo de datos digitales, primero tendremos que encontrar una forma de representarlo en la ((memoria)) de nuestra -máquina.Digamos, como un pequeño ejemplo, que queremos representar una +máquina. Digamos, como un pequeño ejemplo, que queremos representar una ((colección)) de números: 2, 3, 5, 7 y 11. -(((string)))Podríamos ponernos creativos usando cadenas-despues de todo, las -cadenas pueden ser de cualquier longitud, así que podríamos pone mucha -información en ellas-y usar `"2 3 5 7 11"` como nuestra representación. Pero -esto es extaño. De alguna forma tendrías que extaer los dígitos y convertirlos -de vuelta a números para accesarlos. +(((cadena)))Podríamos ponernos creativos usando cadenas; después de todo, las +cadenas pueden ser de cualquier longitud, así que podemos poner mucha +información en ellas; y usar `"2 3 5 7 11"` como nuestra representación. Pero +esto es incómodo. De alguna forma tendrías que extraer los dígitos y convertirlos +de vuelta a números para acceder a ellos. -(((array,creation)))((([] (array))))Afortunadamente, Javascript proporciona un +(((array, creación)))((([] (array))))Afortunadamente, Javascript proporciona un tipo de dato específico para almacenar secuencias de valores. Se le llama -_arreglo_ y se escribe como una lista de valores entre ((corchetes)), separados +_arreglo_ (array) y se escribe como una lista de valores entre ((corchetes)), separados por comas. [source,javascript] ---- -var listOfNumbers = [2, 3, 5, 7, 11]; -console.log(listOfNumbers[1]); +var listaDeNumeros = [2, 3, 5, 7, 11]; +console.log(listaDeNumeros[1]); // → 3 -console.log(listOfNumbers[1 - 1]); +console.log(listaDeNumeros[1 - 1]); // → 2 ---- -((([] (subscript))))(((array,indexing)))La notación para obtener los elementos +((([] (subscript))))(((array,indexado)))La notación para obtener los elementos dentro de un arreglo también utiliza ((corchetes)). Un par de corchetes -inmediátamente después de una expresión, con otra expresión dentro de los -corchetes. buscará el elemento en la expresión de la izquierda que corresponda +inmediatamente después de una expresión, con otra expresión dentro de los +corchetes, buscará el elemento en la expresión de la izquierda que corresponda al _((índice))_ dado por la expresión en corchetes. [[array_indexing]] El primer índice de un arreglo es cero, no uno. Así que el primer elemento puede -leerse usando `listOfNumbers[0]`. Si no tienes antecedentes en programación, +leerse usando `listaDeNumeros[0]`. Si no tienes antecedentes en programación, acostumbrarte a esta convención puede tomarte algún tiempo. Pero el -((zero-based counting)) tiene una larga tradición en tecnología y mientras la -convención se siga de manera consistente (que se ha hecho, en Javascript), +((conteo con base cero)) tiene una larga tradición en tecnología y mientras la +convención se siga de manera consistente (que se ha hecho en Javascript), funciona bien. [[properties]] == Propiedades == -(((Math object)))(((Math.max function)))(((length property,for -string)))(((object,property)))(((period character)))Hemos visto algunas expresiones +(((objeto Math)))(((función Math.max)))(((propiedad length, para +cadenas)))(((object,propiedad)))(((carácter punto)))Hemos visto algunas expresiones sospechosas como `myString.length` (para obtener la longitud de una cadena) y `Math.max` (la función máximo) en ejemplos pasados. Estas son expresiones que -accesan una _((propiedad))_ de algún valor. En el primer caso, accesamos la -propiedad `length` de el valor en `myString`. En el segundo, accesamos la +acceden una _((propiedad))_ de algún valor. En el primer caso, accedemos a la +propiedad `length` de el valor en `myString`. En el segundo, accedemos a la propiedad llamada `max` en el objeto `Math` (que es una colección de valores y funciones relacionadas con las matemáticas). -(((property)))(((null)))(((undefined)))Casi todos los valores de Javascript tienen +(((propiedad)))(((null)))(((undefined)))Casi todos los valores de JavaScript tienen propiedades. Las excepciones son `null` y `undefined`. Si intentas acceder una -propiedad de alguno de estos nonvalues, recibirás un error. +propiedad de alguno de estos valores inválidos recibirás un error. // test: no @@ -140,42 +140,42 @@ null.length; // → TypeError: Cannot read property 'length' of null ---- -indexsee:[dot character,period character] -((([] (subscript))))(((period character)))(((square -brackets)))(((computed property)))Las dos maneras comúnes de accesar propiedades -en Javascript es con un punto y con corchetes. Ambas `value.x` y `value[x]` -accesan una ((propiedad)) en ++value++—pero no necesariamente la misma propiedad. +indexsee:[carácter punto] +((([] (subscript))))(((carácter punto)))(((corchetes)))(((propiedad +calculada)))Las dos maneras comunes de acceder a propiedades +en Javascript son con un punto y con corchetes. Ambas `valor.x` y `valor[x]` +acceden a una ((propiedad)) en ++valor++, pero no necesariamente la misma propiedad. La diferencia radica en cómo se interpreta `x`. Cuando usamos un punto, la parte -después del punto debe ser un nombre de variable válido y nombra de maner a +después del punto debe ser un nombre de variable válido y nombra de manera directa a la propiedad. Cuando usamos corchetes, la expresión dentro de los corchetes es _evaluada_ para obtener el nombre de la propiedad. Mientras que -`value.x` busca la propiedad de `value` llamada “x”, `value[x]` intenta evaluar +`valor.x` busca la propiedad de `valor` llamada “x”, `valor[x]` intenta evaluar la expresión `x` y usa el resultado como el nombre de la propiedad. Así que si sabes que la propiedad que te interesa se llama “length”, usas -`value.length`. Si deseas extraer la propiedad nombrada por el valor almacenado -en la variable`i`, usas `value[i]`. Y debido a que el nombre de las propiedades +`valor.length`. Si deseas extraer la propiedad nombrada por el valor almacenado +en la variable `i`, usas `valor[i]`. Y debido a que el nombre de las propiedades puede ser cualquier cadena, si quieres accesar una propiedad llamada “2” o -“John Doe”, debes utilizar corchetes:`value[2]` or `value["John Doe"]`. Así lo +“Fulano”, debes utilizar corchetes:`valor[2]` or `valor["Fulano de Tal"]`. Así lo harías incluso si conoces el nombre preciso de la propiedad de antemano, ya que -ni “2” ni “John Doe” son nombres válidos de variables y por lo tanto no pueden -accesarse a traves de la notación con punto. +ni “2” ni “Fulano de Tal” son nombres válidos de variables y por lo tanto no puede +accederse a traves de la notación con punto. -(((array)))(((length property,for array)))(((array,length -of)))Los elementos en un arreglo se almacenan en propiedades. Debido a que los +(((arreglo)))(((propiedad length,para arreglo)))(((arreglo,longitud +de)))Los elementos en un arreglo se almacenan en propiedades. Debido a que los nombres de estas propiedades son números y usualmente necesitamos obtener su nombre de una variable, tenemos que usar la sintaxis de corchetes para accesarlos. -La propiedad `length` de un arreglo nos dice cuantos elementos contiene. Este +La propiedad `length` (longitud) de un arreglo nos dice cuantos elementos contiene. Este nombre de propiedad es un nombre de variable válido, y conocemos su nombre por -anticipad, así que para encontrar la longitud de un arreglo, comúnmente -escribiremos `array.length` ya que es más fácil de escribir que `array["length"]`. +anticipado, así que para encontrar la longitud de un arreglo, comúnmente +escribiremos `arreglo.length` ya que es más fácil de escribir que `arreglo["length"]`. [[methods]] == Métodos == -(((function,as property)))(((method)))(((string)))Ambos objetos, las cadenas y -los arreglos contienen, adicionalmente a la propiedad `length`, un número de -propiedades que refieren a valores función. +(((función,como propiedad)))(((método)))(((cadena)))Ambos objetos, las cadenas y +los arreglos contienen, adicionalmente a la propiedad `length` (longitud), varias +propiedades que refieren a valores que son funciones. [source,javascript] ---- @@ -186,24 +186,24 @@ console.log(doh.toUpperCase()); // → DOH ---- -(((case conversion)))(((toUpperCase method)))(((toLowerCase -method)))Todas las cadenas tienen una propiedad `toUpperCase`. Cuando es llamada, +(((conversión de mayúsculas y minúsculas)))(((método toUpperCase)))(((método +toLowerCase)))Todas las cadenas tienen una propiedad `toUpperCase`. Cuando es invocada, regresará una copia de la cadena en la que todas las letras han sido convertidas a mayúsculas. También existe `toLowerCase`. Puedes adivinar que es lo que hace. -(((this)))Interestingly, even though the call to `toUpperCase` does -not pass any arguments, the function somehow has access to the string -`"Doh"`, the value whose property we called. How this works is -described in link:06_object.html#obj_methods[Chapter 6]. +(((this)))Es interesante que, aunque la función `toUpperCase` no +recibe ningún argumento, delaguna forma accede a la cadena `"Doh"`, el +valor en que se llamó la función. Esto funciona como se describe en +el link:06_object.html#obj_methods[Capítulo 6]. -Properties that contain functions are generally called _methods_ of -the value they belong to. As in, “++toUpperCase++ is a method of a -string”. +Las propiedades que contienen funciones genralmente son llamadas _métodos_ +del valor al que pertenecen. Así, "++toUpperCase++ es un método de una cadena". [[array_methods]] -(((collection)))(((array)))(((string)))(((push -method)))(((pop method)))(((join method)))This example demonstrates -some methods that array objects have: +(((colección)))(((array)))(((cadena)))(((método +push)))(((método +pop)))(((método join)))Este ejemplo demuestra +algunos métodos que los objetos arrays tienen: [source,javascript] ---- @@ -220,255 +220,251 @@ console.log(mack); // → ["Mack", "the"] ---- -The `push` method can be used to add values to the end of an array. -The `pop` method does the opposite: it removes the value at the end of -the array and returns it. An array of strings can be flattened to a -single string with the `join` method. The argument given to `join` -determines the text that is glued between the array's elements. +El método `push` puede ser usado para añadir valores al final de un +array. El método `pop` hace lo contrario: elimina el valor al final +del array y lo regresa. Un array de cadenas puede ser transformado a +una sola cadena con el método `join`. El argumento que se da a `join` +determina el texto que se usa entre los elementos del array. -== Objects == +== Objetos == -(((journal)))(((weresquirrel example)))(((array)))(((record)))Back to the weresquirrel. A set of daily log -entries can be represented as an array. But the entries do not consist -of just a number or a string—each entry needs to store a list of -activities and a Boolean value that indicates whether Jacques turned -into a squirrel. Ideally, we would like to group these values together -into a single value and then put these grouped values into an array of -log entries. +(((diario)))(((ejemplo del hombre ardilla)))(((array)))(((registro)))De +regreso con el hombre ardilla. Un conjunto de entradas diaras de registro +pueden ser representadas como un array. Pero las entradas no consisten +de sólo un número o una cadena, cada entrada necesita guarda una lista de +actividades y un valor Booleano que indica si Jacques se convirtió en +ardilla. Idealmente, nos gustaría agrupar estos valores juntos en un solo +valor y poner estos valores agrupados en un array de entradas del registro. -(((syntax)))(((object)))(((property)))(((curly braces)))((({} -(object))))Values of the type _object_ are arbitrary collections of -properties, and we can add or remove these properties as we please. -One way to create an object is by using a curly brace notation. +(((sintaxis)))(((objeto)))(((propiedad)))(((llaves)))((({} +(objeto))))Los valores del tipo _objeto_ son colecciones arbitrarias +de propiedades, y podemos añadir o remover estas propiedades a placer. +Una manera de crear un objeto es usando la notación de llaves. [source,javascript] ---- -var day1 = { - squirrel: false, - events: ["work", "touched tree", "pizza", "running", - "television"] +var dia1 = { + ardilla: false, + eventos: ["trabajo", "toqué un arbol", "pizza", "correr", + "televisión"] }; -console.log(day1.squirrel); +console.log(dia1.ardilla); // → false -console.log(day1.wolf); +console.log(dia1.lobo); // → undefined -day1.wolf = false; -console.log(day1.wolf); +dia1.lobo = false; +console.log(dia1.lobo); // → false ---- -(((quoting,of object properties)))(((colon character)))Inside the -curly braces, we can give a list of properties separated by commas. -Each property is written as a name, followed by a colon, followed by -an expression that provides a value for the property. Spaces and line -breaks are not significant. When an object spans multiple lines, -indenting it like in the previous example improves readability. -Properties whose names are not valid variable names or valid numbers -have to be quoted. +(((entrecomillado,de propiedades de objetos)))(((carácter dos puntos)))Dentro +de las llaves, podemos dar una lista de propiedades separadas por comas. +Cada propiedad está escritra como un nombre seguido por dos puntos, seguidos +pos una expresión que le asigna el valor a esa propiedad. Los espacios +y saltos de línea no son afectan. Cunado un objeto tiene múltiples líneas, +indentarlas como en el ejemplo previo mejora la legibilidad. Las propiedades +que tengan nombres que no sean nombres de variable válidos o números válidos +tienen que estar entrecomilladas. [source,javascript] ---- -var descriptions = { - work: "Went to work", - "touched tree": "Touched a tree" +var descripciones = { + trabajo: "Fui al trabajo", + "toqué un arbol": "Toqué el arbol del vecino" }; ---- -This means that ((curly braces)) have _two_ meanings in JavaScript. At -the start of a statement, they start a block of statements. In any -other position, they describe an object. Fortunately, it is almost -never useful to start a statement with a curly-brace object, and in -typical programs, there is no ambiguity between these two uses. +Esto significa que las ((llaves)) tienen _dos_ significados en JavaScript. +Al principio de una sentencia, empiezan un bloque de sentencia. En cualquier +otra posición, describen un objeto. Afortunadamente, casi nunca es útil +empezar una sentencia con un objeto declarado con llaves, y en programas típicos, +no hay ambigüedad entre esos dos usos. -(((undefined)))Reading a property that doesn't exist will produce the -value `undefined`, which happens the first time we try to read the `wolf` -property in the previous example. +(((undefined)))Al leer una propiedad que no existe se produce el +valor `undefined`, es lo que pasa la primera vez que intentamos leer +la propiedad `lobo` en el ejemplo previo. -(((property,assignment)))(((mutability)))(((= operator)))It is -possible to assign a value to a property expression with the `=` -operator. This will replace the property's value if it already existed -or create a new property on the object if it didn't. +(((propiedad,asignación)))(((mutabilidad)))(((= operador)))Es posible asignar +un valor a una expresión de propiedad con el operador `=`. Esto +reemplazará el valor de la propiedad si ya existía o creará una nueva propiedad +en el objeto si no. -(((tentacle (analogy))))(((property,model of)))To briefly return to -our tentacle model of ((variable)) bindings—property bindings are -similar. They _grasp_ values, but other variables and properties might -be holding onto those same values. You may think of objects as -octopuses with any number of tentacles, each of which has a name -inscribed on it. +(((tentáculo (analogía))))(((propiedad,modelo de)))Para regresar brevemente a nuestro +modelo de tentáculos para asignaciones de ((variable)), la asignación de +propiedades es parecida. Estas _agarran_ valores, pero otras variables y +propiedades pudieran estar agarrando estos mismos valores. Puedes pensar +que los objetos son pulpos con un número indefinido de tentáculos, cada uno +de los cuales tiene un nombre escrito en él. -image::img/octopus-object.jpg[alt="Artist's representation of an object"] +image::img/octopus-object.jpg[alt="Representación de un objeto de un artista."] -(((delete operator)))(((property,deletion)))The `delete` operator cuts -off a tentacle from such an octopus. It is a unary operator that, when -applied to a property access expression, will remove the named -property from the object. This is not a common thing to do, but it is -possible. +(((operador delete)))(((propiedad,borrado)))El operador `delete` le corta un +tentáculo a este pulpo. Es un operador unario que, cuando es aplicado a una +expresión de acceso a una propiedad, eliminará la propiedad nombrada del objeto. +Esto no es algo que se haga comúnmente, pero es posible. [source,javascript] ---- -var anObject = {left: 1, right: 2}; -console.log(anObject.left); +var unObjeto = {izq: 1, der: 2}; +console.log(unObjeto.izq); // → 1 -delete anObject.left; -console.log(anObject.left); +delete unObjeto.izq; +console.log(unObjeto.izq); // → undefined -console.log("left" in anObject); +console.log("izq" in unObjeto); // → false -console.log("right" in anObject); +console.log("der" in unObjeto); // → true ---- -(((in operator)))(((property,testing for)))(((object)))The binary -`in` operator, when applied to a string and an object, returns a -Boolean value that indicates whether that object has that property. -The difference between setting a property to `undefined` and actually -deleting it is that, in the first case, the object still _has_ the -property (it just doesn't have a very interesting value), whereas in -the second case the property is no longer present and `in` will return +(((operador in)))(((propiedad, haciendo pruebas para)))(((objeto)))El operador binario +`in`, cuando se aplica a una cadena y un objeto, devuelve un valor Booleano +que indica si el objeto tiene esa propiedad. La diferencia entre asignarle +`undefined` a una propiedad y borrarla de verdad es que, en el primer caso, +el objeto aún _tiene_ la propiedad (simplemente no tiene un valor muy interesante), +mientras que en el segundo caso, la propiedad no está presente e `in` devolverá `false`. -(((array)))(((collection)))Arrays, then, are just a kind of -object specialized for storing sequences of things. If you evaluate -`typeof [1, 2]`, this produces `"object"`. You can see them as long, -flat octopuses with all their arms in a neat row, labeled with -numbers. +(((array)))(((colección)))Los arrays son solamente un tipo de objeto +especializado en almacenar secuencias de cosas. Si evaluas `typeof [1, 2]`, +se prodcue `"object"`. Puedes verlos como pulpos largos y planos con +todos sus tentáculos en una fila limpia, etiquetados con números. image::img/octopus-array.jpg[alt="Artist's representation of an array"] -(((journal)))(((weresquirrel example)))So we can represent Jacques’ -journal as an array of objects. +(((diario)))(((ejemplo del hombre ardilla)))Así que podemos representar el +diario de Jacques coomo un array de objetos. [source,javascript] ---- -var journal = [ - {events: ["work", "touched tree", "pizza", - "running", "television"], - squirrel: false}, - {events: ["work", "ice cream", "cauliflower", - "lasagna", "touched tree", "brushed teeth"], - squirrel: false}, - {events: ["weekend", "cycling", "break", - "peanuts", "beer"], - squirrel: true}, - /* and so on... */ +var diario = [ + {eventos: ["trabajo", "tocar un arbol", "pizza", + "correr", "televisión"], + ardilla: false}, + {eventos: ["trabajo", "helado", "coliflor", + "lasagna", "tocar un arbol", "lavarse los dientes"], + ardilla: false}, + {eventos: ["fin de seamana", "bicicleta", "descanso", + "cacahuates", "cerveza"], + ardilla: true}, + /* y continúa... */ ]; ---- -== Mutability == +== Mutabilidad == -We will get to actual programming _real_ soon now. But first, there's -one last piece of theory to understand. +Nos meteremos en la programación de verdad pronto. Pero primero, +hay una última pieza de teoría que entender. -(((mutability)))(((side effect)))(((number)))(((string)))(((Boolean)))(((object)))We've seen that object -values can be modified. The types of values discussed in earlier -chapters, such as numbers, strings, and Booleans, are all -__immutable__—it is impossible to change an existing value of those -types. You can combine them and derive new values from them, but when -you take a specific string value, that value will always remain the -same. The text inside it cannot be changed. If you have reference to a -string that contains `"cat"`, it is not possible for other code to -change a character in _that_ string to make it spell `"rat"`. +(((mutabilidad)))(((efecto secundario)))(((número)))(((cadena)))(((Booleano)))(((objeto)))Hemos +visto que los valores objeto pueden ser modificados. Los tipos de +valores de los que platicamos en capítulos anteriores, como números, +cadenas, Booleanos son todos __inmutables__; es imposible cambiar un +valor existente de esos tipos. Puedes combinarlos y derivar nuevos valores de +ellos, pero cuando tomas un valor cadena específico, ese valor siempre +permanecerá igual. El texto que está adentro no puede ser cambiado. Si +tienes una referencia a una cadena que contiene `"cat"`, no se posible +para el código cambiar un caráctes en _esa_ cadena para hacerlo decir `"rat"`. -With objects, on the other hand, the content of a value _can_ be -modified by changing its properties. +Con los objeto, por otro lado, el contenido de un valor _puede_ ser +modificado al cambiar sus propiedades. -(((object,identity)))(((identitiy)))(((memory)))When we have two -numbers, 120 and 120, we can consider them precisely the same number, -whether or not they refer to the same physical bits. But with objects, -there is a difference between having two references to the same object -and having two different objects that contain the same properties. -Consider the following code: +(((objeto,identidad)))(((identidad)))(((memoria)))Cuando tenemos dos +números,, 120 y 120, podemos considerar que son precisamente el mismo número +independientemente si se refieren o no a los mismos bits físicos. Pero +con los objetos, hay una diferencia entre tener la dos referencias al mismo objeto y tener dos objetos que contienen las mismas propiedades. +Considera el siguiente código: [source,javascript] ---- -var object1 = {value: 10}; -var object2 = object1; -var object3 = {value: 10}; +var objeto1 = {valor: 10}; +var objeto2 = objeto1; +var objeto3 = {valor: 10}; -console.log(object1 == object2); +console.log(objeto1 == objeto2); // → true -console.log(object1 == object3); +console.log(objeto1 == objeto3); // → false -object1.value = 15; -console.log(object2.value); +objeto1.valor = 15; +console.log(objeto2.valor); // → 15 -console.log(object3.value); +console.log(objeto3.valor); // → 10 ---- -(((tentacle (analogy))))(((variable,model of)))The `object1` and -`object2` variables grasp the _same_ object, which is why changing -`object1` also changes the value of `object2`. The variable `object3` -points to a different object, which initially contains the same -properties as `object1` but lives a separate life. +(((tentáculo (analogía))))(((variable,modelo de)))Las variables +`objeto1` y `objeto2` agarran el _mismo_ objeto, ésta es la razón +de que al cambiar `objeto1` también se cambia el valor del `objeto2`. +La variable `objeto3` apunta a un objeto diferente, que inicialmente +contiene las mismas propiedades que el `objeto1` pero vive una vida +separada. -(((== operator)))(((comparison,of objects)))(((deep -comparison)))JavaScript's `==` operator, when comparing objects, will -return `true` only if both objects are precisely the same value. -Comparing different objects will return `false`, even if they have -identical contents. There is no “deep” comparison operation built into -JavaScript, which looks at object's contents, but it is possible to -write it yourself (which will be one of the -link:04_data.html#exercise_deep_compare[exercises] at the end of this -chapter). +(((operador ==)))(((comparación,de objetos)))(((comparación +profunda)))El operador `==` de JavaScript, cuando compara objetos +regresará `true` sólo si los dos objetos son precisamente el mismo +valor. Comparar diferentes objetos regresará `false`, incluso si +tienen contenidos idénticos. No existe comparación "profunda" construida en +JavaScript, la cual se basa en el contenido de los objetos, pero puedes +escribirla tú mismo (que será uno de los +link:04_data.html#exercise_deep_compare[ejercicios] al final de este capítulo). -== The lycanthrope's log == +== El registro del licántropo == -(((weresquirrel example)))(((lycanthropy)))(((addEntry function)))So -Jacques starts up his JavaScript interpreter and sets up the -environment he needs to keep his ((journal)). +(((ejemplo del hombre ardilla)))(((licantropía)))(((función agregarEntrada)))Así, +Jacques inicia su intérprete de JavaScript y configura el entorno +que necesita para llevar su ((diario)). // include_code [source,javascript] ---- -var journal = []; +var diario = []; -function addEntry(events, didITurnIntoASquirrel) { - journal.push({ - events: events, - squirrel: didITurnIntoASquirrel +function agregarEntrada(eventos, meVolviArdilla) { + diario.push({ + eventos: eventos, + ardilla: meVolviArdilla }); } ---- -And then, every evening at ten—or sometimes the next morning, after -climbing down from the top shelf of his bookcase—he records the day. +Y después, cada noche a las 10, o algunas veces la mañana siguiente, +después de haber bajado de la parte superior de su librero, registra +el día. [source,javascript] ---- -addEntry(["work", "touched tree", "pizza", "running", - "television"], false); -addEntry(["work", "ice cream", "cauliflower", "lasagna", - "touched tree", "brushed teeth"], false); -addEntry(["weekend", "cycling", "break", "peanuts", - "beer"], true); +agregarEntrada(["trabajo", "toqué un árbol", "pizza", "correr", + "televisión"], false); +agregarEntrada(["trabajo", "helado", "coliflor", "lasagna", + "toqué un árbol", "me lavé los dientes"], false); +agregarEntrada(["fin de semana", "bicicleta", "descanso", "cacachuates", + "cerveza"], true); ---- -Once he has enough data points, he intends to compute the -((correlation)) between his squirrelification and each of the day's -events and ideally learn something useful from those correlations. +Una vez que tiene suficientes datos, quiere calcular la ((correlación)) +entre su ardillamiento y cada uno de los eventos e, idealmente, aprender +algo útil de esas correlaciones. -(((correlation)))_Correlation_ is a measure of ((dependence)) between -((variable))s (“variables” in the statistical sense, not the -JavaScript sense). It is usually expressed as a coefficient that -ranges from -1 to 1. Zero correlation means the variables are not -related, whereas a correlation of one indicates that the two are -perfectly related—if you know one, you also know the other. Negative -one also means that the variables are perfectly related but that they -are opposites—when one is true, the other is false. +(((correlación)))La _Correlación_ es una medida de ((dependencia)) entre +((variable))s (“variables” en el sentido de la estadística, no en el de +JavaScript). Es expresada usualmente como un coeficiente que va del -1 al +1. Una correlación de 0 significa que las variables no están relacionadas, mientras +que una correlación de uno indica que están perfectamente relacionadas: si conoces una, +entonces conoces la otra. El uno negativo también significa que están perfectamente +relacionadas pero que son opuestas, cuando una es verdadera, la otra es falsa. -(((phi coefficient)))For binary (Boolean) variables, the _phi_ -coefficient (_ϕ_) provides a good measure of correlation and is -relatively easy to compute. To compute _ϕ_, we need a ((table)) _n_ -that contains the number of times the various combinations of the two -variables were observed. For example, we could take the event of -eating ((pizza)) and put that in a table like this: +(((coeficiente phi))) Para variables binarias (Booleanas), el coeficiente _phi_ +(_ϕ_) da una buena medida de correlación y es relativamente fácil de calcular. +Para calcular _ϕ_ necesitamos una ((tabla)) _n_ que contine el número de veces +que varias combinaciones de variables fueron observadas. Por ejemplo, podríamos +tomar el evento de comer ((pizza)) y ponerlo en la tabla de la siguiente manera: -image::img/pizza-squirrel.svg[alt="Eating pizza versus turning into a squirrel",width="7cm"] +image::img/pizza-squirrel.svg[alt="Comer pizza vs convertirse en ardilla.",width="7cm"] -_ϕ_ can be computed using the following formula, where _n_ refers to the table: +_ϕ_ puede ser calculado usando la siguiente fórmula, en donde _n_ se refiere a la +tabla: ifdef::html_target[] @@ -495,202 +491,196 @@ pass:[\begin{equation}\varphi = \frac{n_{11}n_{00}-n_{10}n_{01}}{\sqrt{n_{1\bull endif::tex_target[] -The notation (!html _n_~01~!)(!tex pass:[$n_{01}$]!) indicates the -number of measurements where the first variable (squirrelness) is false -(0) and the second variable (pizza) is true (1). In this -example, (!html _n_~01~!)(!tex pass:[$n_{01}$]!) is 9. - -The value (!html _n_~1•~!)(!tex pass:[$n_{1\bullet}$]!) refers to the -sum of all measurements where the first variable is true, which is 5 -in the example table. Likewise, (!html _n_~•0~!)(!tex pass:[$n_{\bullet0}$]!) -refers to the sum of the measurements where the second variable is false. - -(((correlation)))(((phi coefficient)))So for the pizza table, the part -above the division line (the dividend) would be 1×76 - 4×9 = 40, and -the part below it (the divisor) would be the square root of -5×85×10×80, or (!html √340000!)(!tex pass:[$\sqrt{340000}$]!). This -comes out to _ϕ_ ≈ 0.069, which is tiny. Eating ((pizza)) does not -appear to have influence on the transformations. - -== Computing correlation == - -(((array,as table)))(((nesting,of arrays)))We can represent a -two-by-two ((table)) in JavaScript with a four-element array (`[76, 9, -4, 1]`). We could also use other representations, such as an array -containing two two-element arrays (`[[76, 9], [4, 1]]`) or an object -with property names like `"11"` and `"01"`, but the flat array is -simple and makes the expressions that access the table pleasantly -short. We'll interpret the indices to the array as two-((bit)) -((binary number)), where the leftmost (most significant) digit refers -to the squirrel variable and the rightmost (least significant) digit -refers to the event variable. For example, the binary number `10` -refers to the case where Jacques did turn into a squirrel, but the -event (say, "pizza") didn't occur. This happened four times. And since -binary `10` is 2 in decimal notation, we will store this number at -index 2 of the array. - -(((phi coefficient)))(((phi function)))This is the function that -computes the _ϕ_ coefficient from such an array: +La notación (!html _n_~01~!)(!tex pass:[$n_{01}$]!) indica el +número de medidas en el que la primer vairiable (ardillificación) es falsa (0) +y la segunda variable (pizza) es verdadera (1). En este ejemplo, (!html _n_~01~!)(!tex pass:[$n_{01}$]!) es 9. + + +El valor (!html _n_~1•~!)(!tex pass:[$n_{1\bullet}$]!) se refiere a la suma +de todas las medidas en donde la primera variable es verdadera, que es 5 en la tabla de +ejemplo. De la misma manera, (!html _n_~•0~!)(!tex pass:[$n_{\bullet0}$]!) +se refiere a la suma de medidas en donde la segunda variable es falsa. + +(((correlación)))(((coeficiente phi))) Así que para la tabla de la pizza, +la parte de arriba de la línea de división (el dividendo) sería 1×76 - 4×9 = 40, +y la parte de debajo de la línea (el divisor) sería la raíz cuadrada de +5×85×10×80, o (!html √340000!)(!tex pass:[$\sqrt{340000}$]!). Esto da como resultado +_ϕ_ ≈ 0.069, que es muy pequeño. Comer ((pizza)) no parece tener influencia en las transformaciones. + +== Calculando correlaciones == + +(((array,como tabla)))(((anidado, de arrays)))Podemos representar una +((tabla)) de dos por dos en JavaScript con un array de 4 elementos +(`[76, 9, 4, 1]`). Podríamos también usar otras representaciones, como +un array que contenga dos arrays de dos elementos cada uno (`[[76, 9], [4, 1]]`) o como +un objeto con nombre de propiedades como `"11"` y `"01"`, pero el array +plano es simple y hace que las expresiones de acceso a la tabla sean +convenientemente cortas. Interpretaremos los índices del array como +un ((número binario)) de dos ((bit))s, en donde el dígito más a la izquierda +(el más siginificativo) se refiere a la variable de la ardilla y el más a +la derecha (menos significativo) se refiere a la variable del evento. Por ejemplo, +el número binario `10` se refiere al caso en que Jacques se convirtió en +ardilla, pero el evento (digamos, "pizza"), no ocurrió. Esto pasó 4 veces. Y como +el binario `10` es 2 en notación decimal, guardaremos ese número en el índice 2 +del array. + +(((coeficiente phi)))(((función phi)))Esta es la función que calcula el coeficiente +_ϕ_ del ese array: // test: clip // include_code strip_log [source,javascript] ---- -function phi(table) { - return (table[3] * table[0] - table[2] * table[1]) / - Math.sqrt((table[2] + table[3]) * - (table[0] + table[1]) * - (table[1] + table[3]) * - (table[0] + table[2])); +function phi(tabla) { + return (tabla[3] * tabla[0] - tabla[2] * tabla[1]) / + Math.sqrt((tabla[2] + tabla[3]) * + (tabla[0] + tabla[1]) * + (tabla[1] + tabla[3]) * + (tabla[0] + tabla[2])); } console.log(phi([76, 9, 4, 1])); // → 0.068599434 ---- -(((square root)))(((Math.sqrt function)))This is simply a direct -translation of the _ϕ_ formula into JavaScript. `Math.sqrt` is the -square root function, as provided by the `Math` object in a standard -JavaScript environment. We have to sum two fields from the table to -get fields like (!html n~1•~!)(!tex pass:[$n_{1\bullet}$]!) because -the sums of rows or columns are not stored directly in our data -structure. +(((raíz cuadrada)))(((funcieon Math.sqrt)))Esto es simplemente una +traducción directa de la fómula de la _ϕ_ a JavaScript. `Math.sqrt` +es la función raíz cuadrada, provista por el objeto `Math` en un entorno +de JavaScript estándar. Tenemos que sumar los dos campos de la tabla +para obtener campos como (!html n~1•~!)(!tex pass:[$n_{1\bullet}$]!) +porque la suma de las filas o columnas no están guardadas directamente en +nuestra estructura de datos. -(((JOURNAL data set)))Jacques kept his journal for three months. The -resulting ((data set)) is available in the coding sandbox for this -chapter(!book (http://eloquentjavascript.net/code#4[_eloquentjavascript.net/code#4_])!), -where it is stored in the `JOURNAL` variable, and in a downloadable +(((set de datos DIARIO)))Jacques mantuvo su diario por tres meses. El +((set de datos)) resultante está disponible en el área de código para +este capítulo(!book (http://eloquentjavascript.net/code#4[_eloquentjavascript.net/code#4_])!), +en donde está guardada la variable `DIARIO`, y como descarga en http://eloquentjavascript.net/code/jacques_journal.js[file]. -(((tableFor function)))(((hasEvent function)))To extract a two-by-two -((table)) for a specific event from this journal, we must loop over -all the entries and tally up how many times the event occurs in -relation to squirrel transformations. +(((función tablaPara)))(((función tieneEvento)))Para extraer una ((tabla)) de 2 x 2 +po un evento específico de este diario, tenemos que iterar sobre todas las +entradas y contar cuántas veces el evento ocurre en relación con las +transformaciones a ardilla. // include_code strip_log [source,javascript] ---- -function hasEvent(event, entry) { - return entry.events.indexOf(event) != -1; +function tieneEvento(evento, entrada) { + return entrada.eventos.indexOf(evento) != -1; } -function tableFor(event, journal) { - var table = [0, 0, 0, 0]; - for (var i = 0; i < journal.length; i++) { - var entry = journal[i], index = 0; - if (hasEvent(event, entry)) index += 1; - if (entry.squirrel) index += 2; - table[index] += 1; +function tablaPara(evento, diario) { + var tabla = [0, 0, 0, 0]; + for (var i = 0; i < diario.length; i++) { + var entrada = diario[i], index = 0; + if (tieneEvento(evento, entrada)) index += 1; + if (entrada.ardilla) index += 2; + tabla[index] += 1; } - return table; + return tabla; } -console.log(tableFor("pizza", JOURNAL)); +console.log(tabalaPara("pizza", DIARIO)); // → [76, 9, 4, 1] ---- -(((array,searching)))(((indexOf method)))The `hasEvent` function tests -whether an entry contains a given event. Arrays have an `indexOf` -method that tries to find a given value (in this case, the event name) -in the array and returns the index at which it was found or -1 if it -wasn't found. So if the call to `indexOf` doesn't return -1, then we -know the event was found in the entry. +(((array, búsqueda)))(((método indexOf))) La función `tieneEvento` verifica +si una entrada tiene una entrada dada. Los arrays tienen un método +`indexOf` que intenta encontrar un valor dado (en este caso, el nombre del evento) +en el array y regresan el índice en el cuál fue encontrado o -1 si no se encontró. +Así que si la llamada a `indexOf` no regresa -1, entonces sabemos que el evento +fue encontrado en la entrada. -(((array,indexing)))The body of the loop in `tableFor` figures -out which box in the table each journal entry falls into by checking -whether the entry contains the specific event it's interested in and -whether the event happens alongside a squirrel incident. The loop then -adds one to the number in the array that corresponds to this box on -the table. +(((array,indexado)))El cuerpo del loop en `tablaPara` encuentra en qué celda de la +tabla cae cada entrada del diario mediante verificar si la entrada contiene +el evento que está buscando y si el evento ocurre junto con un incidente de ardilla. +Entonces, el loop agrega uno al número en el array que corresponde con esta +categoría en la tabla. -We now have the tools we need to compute individual ((correlation))s. -The only step remaining is to find a correlation for every type of -event that was recorded and see whether anything stands out. But how -should we store these correlations once we compute them? +Ahora tenemos las herramientas que necesitamos para calcular las ((correlaciones)) +individuales. El único paso que queda es encontrar la correlación para +cada tipo de evento registrado y ver si algo sobresale. Pero, ¿cómo debereiamos guardar +esas correlaciones una vez que las calculamos? -== Objects as maps == +== Objetos como mapas == -(((weresquirrel example)))(((array)))One possible way is to store -all the ((correlation))s in an array, using objects with `name` and -`value` properties. But that makes looking up the correlation for a -given event somewhat cumbersome: you'd have to loop over the whole -array to find the object with the right `name`. We could wrap this -lookup process in a function, but we would still be writing more code, -and the computer would be doing more work than necessary. +(((ejemplo del hombre ardilla)))(((array)))Una camino posible es guardar +todas las ((correlaciones)) en un array, usando objetos con propiedades `nombre` y `valor`. +Pero eso hace que buscar la correlación por un evnto dado sea un poco difícil: tienes que +iterar sobre el array completo para buscar el objeto con el `nombre` correcto. Podemos +poner este código en una función, pero seguiríamos escribiendo más código, y la computadora +estaría haciendo más trabajo del necesario. [[object_map]] -(((object)))(((square brackets)))(((object,as map)))(((in -operator)))A better way is to use object properties named after the -event types. We can use the square bracket access notation to create -and read the properties and can use the `in` operator to test whether -a given property exists. +(((objeto)))(((corchetes)))(((object,como mapa)))(((operador in)))Una mejor forma es usar propiedades de +un objeto nombradas como los tipos de eventos. Podemos usar la notación de acceso de corchetes (paréntesis cuadrados) +para crear y leer las propiedades y el operador `in` para verificar si una propiedad existe. [source,javascript] ---- -var map = {}; -function storePhi(event, phi) { - map[event] = phi; +var mapa = {}; +function giardarPhi(evento, phi) { + mapa[evento] = phi; } -storePhi("pizza", 0.069); -storePhi("touched tree", -0.081); -console.log("pizza" in map); +giardarPhi("pizza", 0.069); +giardarPhi("toqué un árbol", -0.081); +console.log("pizza" in mapa); // → true -console.log(map["touched tree"]); +console.log(mapa["touched tree"]); // → -0.081 ---- -(((data structure)))A _((map))_ is a way to go from values in one -domain (in this case, event names) to corresponding values in another -domain (in this case, _ϕ_ coefficients). +(((estructura de datos)))Un _((mapa))_ es una manera de ir de valores en +un dominio (en este caso nombres de eventos) a valores correspondientes +en otro dominio (en este caso coeficientes _ϕ_). -There are a few potential problems with using objects like this, which -we will discuss in link:06_object.html#prototypes[Chapter 6], but for -the time being, we won't worry about those. +Existen algunos problemas potenciales al usar objetos como este, que discutiremos +en el link:06_object.html#prototypes[Capítulo 6], pero por ahora, no nos preocupemos de +eso. -(((for/in loop)))(((for loop)))(((object,looping over)))What if -we want to find all the events for which we have stored a coefficient? -The properties don't form a predictable series, like they would in an -array, so we cannot use a normal `for` loop. JavaScript provides a -loop construct specifically for going over the properties of an -object. It looks a little like a normal `for` loop but distinguishes -itself by the use of the word `in`. +(((loop for/in)))(((loop for)))(((object,iterando))) ¿Y si queremos hallar +todos los eventos para los que tenemos guardados un coeficiente? Las propiedades +no forman una serie predecible, como lo harían en un array, así que no +podemos usar un `for` normal. JavaScript tiene un construcción iterativa +específicamente para funcionar sobre las propiedades de un objeto. Luce un poco como +un loop `for` normal pero se distingue por el uso de la palabra `in`. [source,javascript] ---- -for (var event in map) - console.log("The correlation for '" + event + - "' is " + map[event]); -// → The correlation for 'pizza' is 0.069 -// → The correlation for 'touched tree' is -0.081 +for (var evento in mapa) + console.log("La correlación para '" + evento + + "' es " + mapa[evento]); +// → La correlación para 'pizza' is 0.069 +// → La correlación para 'toqué un arbol' es -0.081 ---- -[[analysis]] -== The final analysis == +[[análisis]] +== El análisis final == -(((journal)))(((weresquirrel example)))(((gatherCorrelations -function)))To find all the types of events that are present in the -data set, we simply process each entry in turn and then loop over the -events in that entry. We keep an object `phis` that has correlation -coefficients for all the event types we have seen so far. Whenever we -run across a type that isn't in the `phis` object yet, we compute its -correlation and add it to the object. +(((diario)))(((ejemplo del hombre ardilla)))(((función +reunirCorrelaciones)))Para encontrar todos los tipos de eventos +que están presentes en el set de datos, simplemente procesamos cada entrada +en turno y después iteramos en los eventos de esa entrada. Mantenemos un objeto +`phis` que tiene los coeficientes de correlación para todos los tipos de eventos que +hemos visto hasta ahora. Cuando encontramos un tipo de evento que no está en el +objeto `phis` todavía, calculamos la correlación y la añadimos al objeto. // test: clip // include_code strip_log [source,javascript] ---- -function gatherCorrelations(journal) { +function gatherCorrelations(diario) { var phis = {}; - for (var entry = 0; entry < journal.length; entry++) { - var events = journal[entry].events; + for (var entry = 0; entry < diario.length; entry++) { + var events = diario[entry].events; for (var i = 0; i < events.length; i++) { var event = events[i]; if (!(event in phis)) - phis[event] = phi(tableFor(event, journal)); + phis[event] = phi(tableFor(event, diario)); } } return phis; @@ -717,11 +707,12 @@ for (var event in correlations) // and so on... ---- -(((for/in loop)))Most correlations seem to lie close to zero. Eating -carrots, bread, or pudding apparently does not trigger -squirrel-lycanthropy. It _does_ seem to occur somewhat more often on -weekends, however. Let's filter the results to show only correlations -greater than 0.1 or less than -0.1. +(((for/in loop)))La mayoría de las correlaciones están cerca de cero. +Comer zanahorias, pan o pudding aparentemente no desencadenan la +licantropía de la ardilla. Sin embargo, parece que sí ocurre más +frecuentemente los fines de semana de alguna manera. Filtremos los +resultados para mostrar sólo las correlaciones mayores que 0.1 o +menores que -0.1. // start_code // test: no @@ -980,7 +971,7 @@ the entries to Jacques’ journal. [source,javascript] ---- -addEntry(["work", "touched tree", "pizza", "running", +addEntry(["work", "touched tree", "pizza", "correr", "television"], false); ---- @@ -1192,10 +1183,12 @@ ifdef::interactive_target[] ---- // Your code here. -console.log(sum(range(1, 10))); -// → 55 +console.log(range(1, 10)); +// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(range(5, 2, -1)); // → [5, 4, 3, 2] +console.log(sum(range(1, 10))); +// → 55 ---- endif::interactive_target[] diff --git a/05_higher_order.txt b/05_higher_order.txt index f5b06b62a..d7fd33516 100644 --- a/05_higher_order.txt +++ b/05_higher_order.txt @@ -180,8 +180,17 @@ forEach(["Wampeter", "Foma", "Granfalloon"], console.log); // → Granfalloon ---- +<<<<<<< HEAD A menudo, no le pasas una función predefinida a `forEach` sino que creas una función en el acto. +======= +(In some browsers, calling `console.log` in this way does not work. +You can use `alert` instead of `console.log` if this example fails to +work.) + +Often, you don't pass a predefined function to `forEach` but create +a function value on the spot instead. +>>>>>>> marijnh/master [source,javascript] ---- @@ -248,63 +257,62 @@ function reuneCorrelaciones(diario) { == Funciones de Orden Superior == -(((function,higher-order)))(((function,as value)))Functions that -operate on other functions, either by taking them as arguments or by -returning them, are called _higher-order functions_. If you have -already accepted the fact that functions are regular values, there is -nothing particularly remarkable about the fact that such functions -exist. The term comes from ((mathematics)), where the distinction -between functions and other values is taken more seriously. +(((función,de orden superior)))(((función,como valor)))Las funciones que +operan en otras funceiones, ya sea tomándolas como argumentos o regresándolas, +son llamadas _funciones de orden superior_. Si ya has aceptado el hecho de que las funciones son +valores reulares, no hay nada de especial en el hecho de que estas funciones +existan. El términos viene de las ((matemáticas)), en dónde la distinción +entre las funciones y otros valores es tomado más seriamente. -(((abstraction)))Higher-order functions allow us to abstract over -_actions_, not just values. They come in several forms. For example, -you can have functions that create new functions. +(((abstracción)))Las funciones de orden superior nos permiten abstraer +_acciones_, no sólo valores. Pueden venir en diferentes formas. Por ejemplo +puedes tener funciones que creen nuevas funciones. [source,javascript] ---- -function greaterThan(n) { +function mayorQue(n) { return function(m) { return m > n; }; } -var greaterThan10 = greaterThan(10); -console.log(greaterThan10(11)); +var mayorQue10 = mayorQue(10); +console.log(mayorQue10(11)); // → true ---- -And you can have functions that change other functions. +Y puedes tener funciones que cambien otras funciones. [source,javascript] ---- -function noisy(f) { +function ruidosa(f) { return function(arg) { - console.log("calling with", arg); + console.log("llamando con", arg); var val = f(arg); - console.log("called with", arg, "- got", val); + console.log("llamada con", arg, "- got", val); return val; }; } -noisy(Boolean)(0); -// → calling with 0 -// → called with 0 - got false +ruidosa(Boolean)(0); +// → llamando con 0 +// → llamada con 0 - obtuve false ---- -You can even write functions that provide new types of ((control flow)). +Incluso puedes escribir funciones que creen nuevos tipos ((control de flujo)). [source,javascript] ---- -function unless(test, then) { - if (!test) then(); +function a_menos_que(condicion, entonces) { + if (!condicion) entonces(); } -function repeat(times, body) { - for (var i = 0; i < times; i++) body(i); +function repetir(veces, cuerpo) { + for (var i = 0; i < veces; i++) cuerpo(i); } -repeat(3, function(n) { - unless(n % 2, function() { - console.log(n, "is even"); +repetir(3, function(n) { + a_menos_que(n % 2, function() { + console.log(n, "es par"); }); }); -// → 0 is even -// → 2 is even +// → 0 es par +// → 2 es par ---- (((inner function)))(((nesting,of functions)))((({} @@ -820,18 +828,18 @@ machine that is me that originates with Pauwels. function)))(((abstraction)))We could also have computed this number without relying on `reduceAncestors`. But separating the general approach (condensing a family tree) from the specific case (computing -shared DNA) can improve the clarity of the code and allows us to -reuse the abstract part of the program for other cases. For example, -the following code finds the percentage of known ancestors, for a -given person, who lived past 70: +shared DNA) can improve the clarity of the code and allows us to reuse +the abstract part of the program for other cases. For example, the +following code finds the percentage of a person's known ancestors who +lived past 70 (by lineage, so people may be counted multiple times): // test: clip [source,javascript] ---- function countAncestors(person, test) { - function combine(person, fromMother, fromFather) { - var thisOneCounts = test(person); + function combine(current, fromMother, fromFather) { + var thisOneCounts = current != person && test(current); return fromMother + fromFather + (thisOneCounts ? 1 : 0); } return reduceAncestors(person, combine, 0); @@ -846,7 +854,7 @@ function longLivingPercentage(person) { return longLiving / all; } console.log(longLivingPercentage(byName["Emile Haverbeke"])); -// → 0.145 +// → 0.129 ---- Such numbers are not to be taken too seriously, given that diff --git a/06_object.txt b/06_object.txt index 6a1833cd3..29c62f701 100644 --- a/06_object.txt +++ b/06_object.txt @@ -768,11 +768,19 @@ soporte subrayado. [source,javascript] ---- +<<<<<<< HEAD function CeldaSubrayada(contenido) { this.contenido = contenido; }; CeldaSubrayada.prototype.minAnchura = function() { return this.contenido.minAnchura(); +======= +function UnderlinedCell(inner) { + this.inner = inner; +} +UnderlinedCell.prototype.minWidth = function() { + return this.inner.minWidth(); +>>>>>>> marijnh/master }; CeldaSubrayada.prototype.minAltura = function() { return this.contenido.minAltura() + 1; diff --git a/07_elife.txt b/07_elife.txt index 1a7cedac3..0bf3c550f 100644 --- a/07_elife.txt +++ b/07_elife.txt @@ -4,44 +4,28 @@ :load_files: ["code/chapter/07_elife.js", "code/animateworld.js"] :zip: html -= Project: Electronic Life = += Proyecto: Vida Electrónica = [chapterquote="true"] [quote, Edsger Dijkstra, The Threats to Computing Science] ____ -[...] the question of whether Machines Can Think [...] is about as -relevant as the question of whether Submarines Can Swim. +[...] La pregunta de si las máquinas pueden pensar [...] es tan relevante como la pregunta de si los submarinos pueden nadar. ____ (((artificial intelligence)))(((Dijkstra+++,+++ Edsger)))(((project chapter)))(((reading code)))(((writing code)))In “project” chapters, -I'll stop pummeling you with new theory for a brief moment and -instead work through a program with you. Theory is indispensable when -learning to program, but it should be accompanied by reading and -understanding nontrivial programs. - -(((artificial life)))(((electronic life)))(((ecosystem)))Our -project in this chapter is to build a virtual ecosystem, a little -world populated with ((critter))s that move around and struggle for -survival. - -== Definition == - -(((dimensions)))(((electronic life)))To make this -task manageable, we will radically simplify the concept of a -_((world))_. Namely, a world will be a two-dimensional ((grid)) where -each entity takes up one full square of the grid. On every _((turn))_, -the critters all get a chance to take some action. - -(((discretization)))(((simulation)))Thus, we chop both time and space -into units with a fixed size: squares for space and turns for time. Of -course, this is a somewhat crude and inaccurate ((approximation)). But -our simulation is intended to be amusing, not accurate, so we can -freely cut such corners. +En los capítulos de proyecto, dejaré de abrumarte con teoría nueva por un breve momento, y en lugar de eso trabajaremos a través de un programa juntos. La teoría es indispensable cuando aprendemos a programar, pero debería ser acompañada de lecturas y la comprensión de programas no triviales. + +(((artificial life)))(((electronic life)))(((ecosystem)))Nuestro proyecto en este capítulo es construir un ecosistema virtual, un mundo pequeño poblado con bichos que se mueven alrededor y luchan por sobrevivir. + +== Definición == + +(((dimensions)))(((electronic life)))Para hacer esta tarea manejable, nosotros simplificaremos radicalmente el concepto de mundo (_((world))_). Es decir un mundo será una cuadricula de dos dimensiones donde cada entidad ocupa un cuadro completo de ella. En cada _((turn))_, todos los bichos tienen oportunidad de hacer alguna acción. + +(((discretization)))(((simulation)))Por lo tanto, cortamos ambos tiempo y espacio en dos unidades con un tamaño fijo: cuadros para espacio y turnos para tiempo. Por supuesto, esto es una burda e imprecisa ((aproximación)). Pero nuestra simulación pretende ser entretenida, no precisa, así que podemos acortar libremente las dimensiones. [[plan]] -(((array)))We can define a world with a _plan_, an array of -strings that lays out the world's grid using one character per square. +(((array)))Podemos definir un mundo como un _plan_, una matriz de cadenas que establece la cuadrícula del mundo usando un carácter por cuadro. . // include_code @@ -60,28 +44,15 @@ var plan = ["############################", "# # #", "############################"]; ---- +El carácter "#" en este programa representa paredes y rocas, y el carácter "o" representa bichos (_critters_). Los espacios, como posiblemente habrás adivinado, son espacios vacíos. -The “#” characters in this plan represent ((wall))s and rocks, and the -“o” characters represent critters. The spaces, as you might have -guessed, are empty space. - -(((object)))(((toString method)))(((turn)))A plan array can be -used to create a ((world)) object. Such an object keeps track of the -size and content of the world. It has a `toString` method, which -converts the world back to a printable string (similar to the plan it -was based on) so that we can see what's going on inside. The world -object also has a `turn` method, which allows all the critters in it to -take one turn and updates the world to reflect their actions. +(((object)))(((toString method)))(((turn)))Una matriz unidimensional puede ser usada para crear un objeto mundo (_world_). Tal objeto mantiene seguimiento del tamaño y el contenido. El mundo tiene un método _toString_ que convierte al mundo nuevamente en una cadena imprimible (parecida al programa en el que se basó) de manera que podamos ver qué es lo que está pasando dentro. El objeto mundo también tiene un método _turn_, el cual permite a todos los bichos que lo habitan tomar un turno y luego actualizar el mundo reflejando sus acciones. [[grid]] -== Representing space == +== Representando el espacio. == -(((array,as grid)))(((Vector type)))(((coordinates)))The ((grid)) -that models the world has a fixed width and height. Squares are -identified by their x- and y-coordinates. We use a simple type, -`Vector` (as seen in the exercises for the -link:06_object.html#exercise_vector[previous chapter]), to represent -these coordinate pairs. +(((array,as grid)))(((Vector type)))(((coordinates))) +La cuadrícula (_grid_) que modela el mundo tiene un ancho y altura fija. Los cuadros son identificados por sus coordenadas "X" y "Y". Usamos un tipo sencillo, _Vector_ (como los vistos en los ejercicios del link:06_object.html#exercise_vector[capítulo anterior]), para representar estas coordenadas en pares. // include_code @@ -96,15 +67,9 @@ Vector.prototype.plus = function(other) { }; ---- -(((object)))(((encapsulation)))Next, we need an object type that -models the grid itself. A grid is part of a world, but we are making -it a separate object (which will be a property of a ((world)) object) -to keep the world object itself simple. The world should concern -itself with world-related things, and the grid should concern itself with grid-related things. +(((object)))(((encapsulation))) A continuacion, necesitamos un tipo de objeto que modele por si mismo la cuadricula (_grid_). La cuadricula es parte del mundo, pero nosotros estamos haciendo la cuadricula como un objeto separado (que sera una propiedad del objeto mundo) para mantener el objeto _world_ simple. El mundo debe ocuparse de las cosas relacionadas con el mundo, y la cuadricula debe ocuparse de las cosas relacionadas con la cuadricula. -(((array)))(((data structure)))To store a grid of values, we have -several options. We can use an array of row arrays and use two -property accesses to get to a specific square, like this: +(((array)))(((data structure)))Para almacenar una cuadricula de valores, tenemos varias opciones. Podemos utilizar una matriz de matrices de filas (_array of row arrays_) y utilizar dos propiedades de acceso para llegar a una cruadricula específica: [source,javascript] ---- @@ -114,9 +79,7 @@ console.log(grid[1][2]); // → bottom right ---- -(((array,indexing)))(((coordinates)))(((grid)))Or we can use a -single array, with size width × height, and decide that the element at -(_x_,_y_) is found at position _x_ + (_y_ × width) in the array. +(((array,indexing)))(((coordinates)))(((grid)))O podemos utilizar una sola matriz, con el tamaño de ancho x alto, y decidir que el elemento en (_x_,_y_) se encuentra en la posición _x_ + (_y_ x ancho) de la matriz. [source,javascript] ---- @@ -127,15 +90,9 @@ console.log(grid[2 + (1 * 3)]); ---- (((encapsulation)))(((abstraction)))(((Array constructor)))(((array,creation)))(((array,length -of)))Since the actual access to this array will be wrapped in methods -on the grid object type, it doesn't matter to outside code which -approach we take. I chose the second representation because it makes -it much easier to create the array. When calling the `Array` -constructor with a single number as an argument, it creates a new empty -array of the given length. +of)))Dado que el acceso real a esta matriz (_Array_) será envuelto en métodos en el objeto de tipo cuadricula, no le importa al código externo cual enfoque tomamos. Elegí la segunda representación, ya que hace que sea mucho más fácil crear la matriz. Al llamar al constructor de _Array_ con un solo número como argumento, se crea una nueva matriz vacía de la longitud dada. -(((Grid type)))This code defines the `Grid` object, with some basic -methods: +(((Grid type)))Este código define el objeto cuadricula (_Grid_) con algunos métodos básicos: // include_code @@ -158,7 +115,7 @@ Grid.prototype.set = function(vector, value) { }; ---- -And here is a trivial test: +Y aquí es una prueba trivial: [source,javascript] ---- @@ -170,27 +127,12 @@ console.log(grid.get(new Vector(1, 1))); // → X ---- -== A critter's programming interface == +== Una interfaz para programar bichos (_critter_) == -(((record)))(((electronic life)))(((interface)))Before we can -start on the `World` ((constructor)), we must get more specific about -the ((critter)) objects that will be living inside it. I mentioned -that the world will ask the critters what actions they want to take. -This works as follows: each critter object has an `act` ((method)) -that, when called, returns an _action_. An action is an object with a -`type` property, which names the type of action the critter wants to -take, for example `"move"`. The action may also contain extra -information, such as the direction the critter wants to move in. +(((record)))(((electronic life)))(((interface)))Antes de que podamos comenzar con nuestro _constructor_ en nuestro mundo, debemos obtener más especificaciones sobre los objetos _critter_ que estarán viviendo dentro de él. Mencioné que el mundo preguntará a las criaturas qué acciones quieren tomar. Esto funciona de esta manera: cada objeto _critter_ tiene un método _act_ que, cuando se lo llama, devuelve una acción. Una acción es un objeto con una propiedad de tipo (_type_), que indica el tipo de acción que el _critter_ quiere tomar, por ejemplo "mover". La acción también puede contener información adicional, como la dirección en la que el _critter_ quiere moverse. [[directions]] -(((Vector type)))(((View type)))(((directions object)))(((object,as map)))Critters are terribly myopic and can see only the -squares directly around them on the grid. But even this limited vision -can be useful when deciding which action to take. When the `act` -method is called, it is given a _view_ object that allows the critter -to inspect its surroundings. We name the eight surrounding squares by -their ((compass direction))s: `"n"` for north, `"ne"` for northeast, -and so on. Here's the object we will use to map from direction names -to coordinate offsets: +(((Vector type)))(((View type)))(((directions object)))(((object,as map)))Los _Critters_ son terriblemente miopes y pueden ver solamente los cuadrados directamente alrededor de ellos en la cuadricula. Pero incluso esta visión limitada puede ser útil al decidir qué acción tomar. Cuando se llama al método _act_, se recibe un objeto _view_ que permite al _critter_ inspeccionar su entorno. Nombramos los ocho cuadrados circundantes por sus direcciones de la brújula: "_n_" para el norte, "_ne_" para el noreste, y así sucesivamente. Este es el objeto que usaremos para asignar los nombres de dirección a los desplazamientos de coordenadas: // include_code @@ -208,20 +150,9 @@ var directions = { }; ---- -(((View type)))The view object has a method `look`, which takes a -direction and returns a character, for example `"#"` when there is a -wall in that direction, or `" "` (space) when there is nothing there. -The object also provides the convenient methods `find` and `findAll`. -Both take a map character as an argument. The first returns a direction -in which the character can be found next to the critter or returns `null` if -no such direction exists. The second returns an array containing all -directions with that character. For example, a creature sitting left -(west) of a wall will get `["ne", "e", "se"]` when calling `findAll` -on its view object with the `"#"` character as argument. +(((View type)))El objeto _view_ tiene un método _look_, que toma una dirección y devuelve un carácter, por ejemplo "_#_" cuando hay una pared en esa dirección, o " " (espacio) cuando no hay nada allí. El objeto también proporciona los métodos convenientes _find_ y _findAll_. Ambos toman un carácter de mapa como argumento. El primero devuelve una dirección en la que el carácter se puede encontrar con respecto al _critter_ o devuelve _null_ si no existe tal dirección. El segundo devuelve una matriz que contiene todas las direcciones con ese carácter. Por ejemplo, una criatura sentada a la izquierda (al oeste) de una pared obtendrá ["_ne_", "_e_", "_se_"] al llamar a _findAll_ en su objeto de vista con el carácter "_#_" como argumento. -(((bouncing)))(((behavior)))(((BouncingCritter type)))Here is a -simple, stupid critter that just follows its nose until it hits an -obstacle and then bounces off in a random open direction: +(((bouncing)))(((behavior)))(((BouncingCritter type)))Aquí está un _critter_ simple y estúpido que sigue su nariz hasta que golpea un obstáculo y luego rebota en una dirección al azar: // include_code @@ -245,35 +176,15 @@ BouncingCritter.prototype.act = function(view) { ---- (((random number)))(((Math.random function)))(((randomElement -function)))(((array,indexing)))The `randomElement` helper -function simply picks a random element from an array, using -`Math.random` plus some arithmetic to get a random index. We'll use -this again later because randomness can be useful in ((simulation))s. - -(((Object.keys function)))To pick a random direction, the -`BouncingCritter` constructor calls `randomElement` on an array of -direction names. We could also have used `Object.keys` to get this -array from the `directions` object we defined -link:07_elife.html#directions[earlier], but that provides no -guarantees about the order in which the properties are listed. In most -situations, modern JavaScript engines will return properties in the -order they were defined, but they are not required to. - -(((|| operator)))(((null)))The “++|| "s"++” in the `act` method is -there to prevent `this.direction` from getting the value `null` if the -critter is somehow trapped with no empty space around it (for example -when crowded into a corner by other critters). - -== The world object == - -(((World type)))(((electronic life)))Now we can start on the -`World` object type. The ((constructor)) takes a plan (the array of -strings representing the world's grid, described -link:07_elife.html#grid[earlier]) and a _((legend))_ as arguments. A -legend is an object that tells us what each character in the map -means. It contains a constructor for every character—except for the -space character, which always refers to `null`, the value we'll use to -represent empty space. +function)))(((array,indexing)))La función de ayuda _randomElement_ simplemente selecciona un elemento aleatorio de una matriz (_Array_), usando _Math.random_ más algún cálculo aritmético obtendremos un índice aleatorio. Esto lo usaremos más adelante porque la aleatoriedad puede ser útil en simulaciones. + +(((Object.keys function)))Para escoger una dirección aleatoria, el constructor _BouncingCritter_ llama a _randomElement_ en una matriz _directionNames_. También podríamos haber usado _Object.keys_ para obtener esta matriz del objeto _directions_ que definimos anteriormente, pero eso no proporciona garantías sobre el orden en el que se enumeran las propiedades. En la mayoría de las situaciones, los motores de JavaScript modernos devolverán las propiedades en el orden en que se definieron, pero no necesariamente. + +(((|| operator)))(((null)))El “++|| "S"++” en el método _act_ está ahí para evitar que _this.direction_ de valor _null_ si el _critter_ está de alguna manera atrapado sin espacio vacío alrededor de él (por ejemplo, cuando se aglomeran en una esquina con otros _critters_). + +== El objeto del mundo == + +(((World type)))(((electronic life)))Ahora podemos comenzar con el tipo de objeto _World_. El constructor toma un plan (la matriz de cadenas que representa la cuadrícula del mundo, link:07_elife.html#grid[descrita] anteriormente) y una leyenda (_legend_) como argumentos. Una leyenda es un objeto que nos dice qué significa cada carácter en el mapa. Contiene un constructor para cada carácter, excepto el carácter de espacio, que siempre refiere a _null_ y es el valor que usaremos para representar el espacio vacío. // include_code @@ -300,17 +211,10 @@ function World(map, legend) { } ---- -(((elementFromChar function)))(((object,as map)))In `elementFromChar`, -first we create an instance of the right type by looking up the -character's constructor and applying `new` to it. Then we add an -`originChar` ((property)) to it to make it easy to find out what -character the element was originally created from. +(((elementFromChar function)))(((object,as map)))En _elementFromChar_, primero creamos una _instance_ del tipo correcto buscando el constructor del carácter y aplicándole _new_. A continuación, agregamos una propiedad _originChar_ a ella para que sea fácil averiguar de qué carácter se creó el elemento originalmente. (((toString method)))(((nesting,of loops)))(((for -loop)))(((coordinates)))We need this `originChar` property when -implementing the world's `toString` method. This method builds up a -maplike string from the world's current state by performing a -two-dimensional loop over the squares on the grid. +loop)))(((coordinates)))Necesitamos esta propiedad _originChar_ al implementar el método _toString_ de _word_. Este método construye una cadena _maplike_ del estado actual del mundo realizando un bucle bidimensional sobre los cuadros de la cuadrícula. // include_code @@ -336,9 +240,7 @@ World.prototype.toString = function() { }; ---- -(((electronic life)))(((constructor)))(((Wall type)))A ((wall)) is -a simple object—it is used only for taking up space and has no -`act` method. +(((electronic life)))(((constructor)))(((Wall type)))Una pared es un objeto simple: se usa sólo para ocupar espacio y no tiene método _act_. // include_code @@ -347,10 +249,7 @@ a simple object—it is used only for taking up space and has no function Wall() {} ---- -(((World type)))When we try the `World` object by creating an -instance based on the plan from link:07_elife.html#plan[earlier in the -chapter] and then calling `toString` on it, we get a string very -similar to the plan we put in. +(((World type)))Cuando probamos el objeto _World_ creando una instancia basada en el plan del link:07_elife.html#plan[capítulo anterior] y luego invocando _toString_ sobre él, obtenemos una cadena muy similar al plan. // include_code strip_log // test: trim @@ -374,34 +273,18 @@ console.log(world.toString()); // ############################ ---- -== this and its scope == +== _This_ y su alcance == (((forEach method)))(((function,scope)))(((this)))(((scope)))(((self -variable)))(((global object)))The `World` ((constructor)) contains a -call to `forEach`. One interesting thing to note is that inside the -function passed to `forEach`, we are no longer directly in the -function scope of the constructor. Each function call gets its own -`this` binding, so the `this` in the inner function does _not_ -refer to the newly constructed object that the outer `this` refers to. -In fact, when a function isn't called as a method, `this` will refer -to the global object. - -This means that we can't write `this.grid` to access the grid from -inside the ((loop)). Instead, the outer function creates a normal -local variable, `grid`, through which the inner function gets access -to the grid. +variable)))(((global object)))El constructor _World_ contiene una llamada a _forEach_. Una cosa interesante a notar es que dentro de la función pasada a _forEach_ ya no estamos directamente en el ámbito de funciones del _constructor_. Cada llamada de función obtiene su propia vinculación para _this_, por lo que el _this_ en la función interna no se refiere al mismo objeto en la­ nueva construcción que se refiere _this_ en la funcion externa. De hecho, cuando una función no se llama como un (método), _this_ hará referencia al objeto global. + +Esto significa que no podemos escribir _this.grid_ para acceder a la cuadrícula desde dentro del bucle. En su lugar, la función externa crea una variable local normal, _grid_, a través de la cual la función interna obtiene acceso a la cuadrícula. (((future)))(((ECMAScript 6)))(((arrow function)))(((self -variable)))This is a bit of a design blunder in JavaScript. -Fortunately, the next version of the language provides a solution for -this problem. Meanwhile, there are workarounds. A common pattern is to -say `var self = this` and from then on refer to `self`, which is a -normal variable and thus visible to inner functions. +variable)))Esto es un poco un error de diseño en JavaScript. Afortunadamente, la siguiente versión del lenguaje proporciona una solución para este problema. Mientras tanto, hay soluciones. Un patrón común es decir _var self = this_ y a partir de entonces se refiere a _self_, que es una variable normal y, por lo tanto, visible a las funciones internas. -(((bind method)))(((this)))Another solution is to use the `bind` -method, which allows us to provide an explicit `this` object to bind -to. +(((bind method)))(((this)))Otra solución es utilizar el método _bind_, que nos permite proporcionar un objeto explícito a enlazar. [source,javascript] ---- @@ -417,16 +300,9 @@ console.log(test.addPropTo([5])); // → [15] ---- -(((map method)))The function passed to `map` is the result of the -`bind` call and thus has its `this` bound to the first argument given -to ++bind++—the outer function's `this` value (which holds the `test` -object). +(((map method)))La función pasada al _map_ es el resultado de la llamada de enlace (_bind call_) y por lo tanto _this_ está vinculado al primer argumento dado a _bind_, el valor _this_ de la función externa (que contiene el objeto de prueba). -(((context parameter)))(((function,higher-order)))Most ((standard)) -higher-order methods on arrays, such as `forEach` and `map`, take an -optional second argument that can also be used to provide a `this` for -the calls to the iteration function. So you could express the previous example -in a slightly simpler way. +(((context parameter)))(((function,higher-order)))La mayoría de los métodos estándar de orden superior en matrices (_arrays_), como _forEach_ y _map_, toman un segundo argumento opcional que también se puede utilizar para proporcionar un _this_ para las llamadas a la función de iteración. Así que podría expresar el ejemplo anterior de una manera un poco más simple. [source,javascript] ---- @@ -442,16 +318,9 @@ console.log(test.addPropTo([5])); // → [15] ---- -This works only for higher-order functions that -support such a _context_ parameter. When they don't, you'll need to -use one of the other approaches. +Esto sólo funciona para las funciones de orden superior que soportan dicho parámetro de contexto. Cuando no lo hacen, tendrá que utilizar uno de los otros enfoques. -(((context parameter)))(((function,higher-order)))(((call method)))In -our own higher-order functions, we can support such a context -parameter by using the `call` method to call the function given as an -argument. For example, here is a `forEach` method for our `Grid` type, -which calls a given function for each element in the grid that isn't -null or undefined: +(((context parameter)))(((function,higher-order)))(((call method)))En nuestras propias funciones de orden superior, podemos utilizar este parámetro de contexto utilizando el método _call_ para llamar a la función dada como argumento. Por ejemplo, aquí hay un método _forEach_ para nuestro tipo _Grid_, que llama a una función dada para cada elemento de la cuadrícula que no es _null_ o _undefined_: // include_code @@ -468,22 +337,11 @@ Grid.prototype.forEach = function(f, context) { }; ---- -== Animating life == +== Animando la vida == -(((simulation)))(((electronic life)))(((World type)))The next -step is to write a `turn` method for the world object that gives the -((critter))s a chance to act. It will go over the grid using the -`forEach` method we just defined, looking for objects with an `act` -method. When it finds one, `turn` calls that method to get an action -object and carries out the action when it is valid. For now, only -`"move"` actions are understood. +(((simulation)))(((electronic life)))(((World type)))El siguiente paso es escribir un método de _turn_ para el objeto _word_ que da a los bichos la oportunidad de actuar. Recorrerá la cuadrícula usando el método _forEach_ que acabamos de definir, buscando objetos con un método _act_. Cuando encuentre uno, _turn_ llamadra dicho método _act_ para obtener un objeto y llevar a cabo ese tipo de acción. Por ahora, solo se entienden las acciones tipo "mover". -(((grid)))There is one potential problem with this approach. Can you -spot it? If we let critters move as we come across them, they may move -to a square that we haven't looked at yet, and we'll allow them to -move _again_ when we reach that square. Thus, we have to keep an array -of critters that have already had their turn and ignore them when we -see them again. +(((grid)))Hay un problema potencial con este enfoque. ¿Puedes detectarlo? Si dejamos que los bichos se muevan al cruzarlos, pueden moverse a un cuadrado que todavía no hemos visto, y les permitiremos moverse de nuevo cuando alcancemos ese cuadrado. Por lo tanto, tenemos que mantener una serie de criaturas que ya han tenido su turno e ignorarlos cuando los vemos de nuevo. // include_code @@ -500,10 +358,7 @@ World.prototype.turn = function() { }; ---- -(((this)))We use the second parameter to the grid's `forEach` method -to be able to access the correct `this` inside the inner function. -The `letAct` method contains the actual logic that allows the critters -to move. +(((this)))Utilizamos el segundo parámetro del método _forEach_ de la cuadrícula para poder acceder al _this_ correcto dentro de la función interna. El método _letAct_ contiene la lógica real que permite a los _critters_ moverse. // include_code @@ -530,46 +385,19 @@ World.prototype.checkDestination = function(action, vector) { }; ---- -(((View type)))(((electronic life)))First, we simply ask the -critter to act, passing it a view object that knows about the world -and the critter's current position in that world (we'll define `View` -in a link:07_elife.html#view[moment]). The `act` method returns an -action of some kind. +(((View type)))(((electronic life)))Primero, pedimos simplemente al _critter_ que actúe, pasándola un objeto _view_ con datos sobre el mundo y la posición actual de la criatura (definiremos _view_ en un link:07_elife.html#view[momento]). El método _act_ devuelve una acción de algún tipo. -If the action's `type` is not `"move"`, it is ignored. If it _is_ -`"move"`, if it has a `direction` property that refers to a valid -direction, _and_ if the square in that direction is empty (null), we set -the square where the critter used to be to hold null and store the -critter in the destination square. +Si el tipo (_type_) de la acción no es "mover", se ignora. Si es "mover", si tiene una propiedad de dirección que se refiere a una dirección válida, y si el cuadrado en esa dirección es vacío (_null_), fijamos el cuadrado donde el _critter_ estaba como _null_ y almacenamos el critter en el cuadrado de destino. (((error tolerance)))(((defensive programming)))(((sloppy -programming)))(((validation)))Note that `letAct` takes care to ignore -nonsense ((input))—it doesn't assume that the action's `direction` -property is valid or that the `type` property makes sense. This kind -of _defensive_ programming makes sense in some situations. The main -reason for doing it is to validate inputs coming from sources you -don't control (such as user or file input), but it can also be useful -to isolate subsystems from each other. In this case, the intention is -that the critters themselves can be programmed sloppily—they don't -have to verify if their intended actions make sense. They can just -request an action, and the world will figure out whether to allow it. +programming)))(((validation)))Tenga en cuenta que _letAct_ se encarga de ignorar la entrada no valida, no asume que la propiedad _direction_ de la acción es válida o que la propiedad _type_ tiene sentido. Este tipo de (programación defensiva) tiene sentido en algunas situaciones. La principal razón para hacerlo es validar entradas procedentes de fuentes que no controla (como la entrada de usuario o de archivo), pero también puede ser útil para aislar subsistemas entre sí. En este caso, la intención es que los _critters_ puedan ser programados descuidadamente (no tienen que verificar si sus acciones previstas tienen sentido. Pueden solicitar una acción, y el mundo averiguará si permitirla). (((interface)))(((private property)))(((access control)))(((property,naming)))(((underscore character)))(((World -type)))These two methods are not part of the external interface of a -`World` object. They are an internal detail. Some languages provide -ways to explicitly declare certain methods and properties _private_ -and signal an error when you try to use them from outside the object. -JavaScript does not, so you will have to rely on some other form of -communication to describe what is part of an object's interface. -Sometimes it can help to use a naming scheme to distinguish between -external and internal properties, for example by prefixing all -internal ones with an underscore character (_). This will make -accidental uses of properties that are not part of an object's -interface easier to spot. +type)))Estos dos métodos no forman parte de la interfaz externa de un objeto _World_. Ellos son un detalle interno. Algunos lenguajes proporcionan formas de declarar explícitamente ciertos métodos y propiedades privadas y señalan un error cuando intenta utilizarlos desde fuera del objeto. JavaScript no, por lo que tendrá que depender de alguna otra forma de comunicación para describir lo que es parte de la interfaz de un objeto. A veces puede ayudar utilizar un esquema de nomenclatura para distinguir entre propiedades externas e internas, por ejemplo prefijando todas las internas con un carácter de subrayado (_). Esto hará que los usos accidentales de las propiedades que no sean parte de la interfaz de un objeto sean más fáciles de detectar. [[view]] -(((View type)))The one missing part, the `View` type, looks like this: +(((View type)))La parte que falta, el tipo _view_, se parece a esto: // include_code @@ -600,18 +428,11 @@ View.prototype.find = function(ch) { }; ---- -(((defensive programming)))The `look` method figures out the -coordinates that we are trying to look at and, if they are inside the -((grid)), finds the character corresponding to the element that sits -there. For coordinates outside the grid, `look` simply pretends that -there is a wall there so that if you define a world that isn't walled -in, the critters still won't be tempted to try to walk off the edges. +(((defensive programming)))El método _look_ calcula las coordenadas que estamos tratando de ver y, si están dentro de la cuadrícula, encuentra el carácter correspondiente al elemento que se encuentra allí. Para las coordenadas fuera de la cuadrícula, _look_ simplemente finge que hay una pared allí de modo que si usted define un mundo sin paredes, las criaturasno serán tentadas de intentar caminar fuera de los bordes. -== It moves == +== Se mueve == -(((electronic life)))(((simulation)))We instantiated a world -object earlier. Now that we've added all the necessary methods, it -should be possible to actually make the world move. +(((electronic life)))(((simulation)))Hemos instanciado un objeto del mundo anterior. Ahora que hemos añadido todos los métodos necesarios, debería ser posible hacer que el mundo se mueva. [source,javascript] ---- @@ -624,8 +445,8 @@ for (var i = 0; i < 5; i++) { ifdef::book_target[] -The first two maps that are displayed will look something like this -(depending on the random direction the critters picked): + +Los primeros dos mapas que se muestran será algo similar a esto: ---- ############################ ############################ @@ -642,20 +463,14 @@ The first two maps that are displayed will look something like this ############################ ############################ ---- -(((animation)))They move! To get a more interactive view of these -critters crawling around and bouncing off the walls, open this chapter -in the online version of the book at -http://eloquentjavascript.net[_eloquentjavascript.net_]. +(((animation))) ¡Ellos mueven! Para obtener una visión más interactiva de estas +criaturas que se arrastran y rebotan en las paredes, abra este capítulo en la versión on-line del libro http://eloquentjavascript.net[_eloquentjavascript.net_]. endif::book_target[] ifdef::interactive_target[] -Simply printing out many copies of the map is a rather unpleasant -way to observe a world, though. That's why the sandbox provides an -`animateWorld` function that will run a world as an onscreen -animation, moving three turns per second, until you hit the stop -button. +Sin embargo, imprimir muchas copias del mapa es una manera bastante desagradable de observar un mundo. Es por eso que el _sandbox_ proporciona una función _animateWorld_ que ejecutará un mundo como una animación en pantalla, moviéndose tres veces por segundo, hasta que pulse el botón de parada. // test: no @@ -665,31 +480,17 @@ animateWorld(world); // → … life! ---- -The implementation of `animateWorld` will remain a mystery for now, -but after you've read the link:13_dom.html#dom[later chapters] of this -book, which discuss JavaScript integration in web browsers, it won't -look so magical anymore. +La implementación de _animateWorld_ seguirá siendo un misterio por ahora, pero después de haber leído los link:13_dom.html#dom[capítulos posteriores] de este libro, y estudiar la integración de JavaScript en los navegadores web, ya no se verá tan mágico. endif::interactive_target[] -== More life forms == +== Más formas de vida == -The dramatic highlight of our world, if you watch for a bit, is when -two critters bounce off each other. Can you think of another -interesting form of ((behavior))? +El punto culminante dramático de nuestro mundo, si usted mira para un pedacito, es cuando dos _critters_ rebotan el uno al otro. ¿Puedes pensar en otra forma interesante de ((comportamiento))? -(((wall following)))The one I came up with is a ((critter)) that moves -along walls. Conceptually, the critter keeps its left hand (paw, -tentacle, whatever) to the wall and follows along. This turns out to -be not entirely trivial to implement. +(((wall following)))Podemos hacer un _critter_ que se mueve a lo largo de las paredes (_WallFollower_). Conceptualmente, el critter mantiene su mano izquierda (pata, tentáculo, lo que sea) a la pared y sigue adelante. Este no es un cambio trivial de implementar: -(((WallFollower type)))(((directions object)))We need to be -able to “compute” with ((compass direction))s. Since directions are -modeled by a set of strings, we need to define our own operation -(`dirPlus`) to calculate relative directions. So `dirPlus("n", 1)` -means one 45-degree turn clockwise from north, giving `"ne"`. -Similarly, `dirPlus("s", -2)` means 90 degrees counterclockwise from -south, which is east. +(((WallFollower type)))(((directions object))) Tenemos que ser capaces de “hacer calculos" con las ((direcciones de la brújula)). Como las direcciones son modeladas por un conjunto de cadenas, deberíamos definir nuestra propia operación (_dirPlus_) para calcular direcciones relativas. Así dirPlus ("_n_", _1_) significa una vuelta de 45 grados en sentido horario desde el norte, dando "_ne_". Del mismo modo, dirPlus ("_s_", _-2_) significa 90 grados en sentido antihorario desde el sur, que es el este. // include_code @@ -716,31 +517,17 @@ WallFollower.prototype.act = function(view) { }; ---- -(((artificial intelligence)))(((pathfinding)))(((View type)))The `act` -method only has to “scan” the critter's surroundings, starting from -its left side and going clockwise until it finds an empty square. -It then moves in the direction of that empty square. +(((artificial intelligence)))(((pathfinding)))(((View type)))El método _act_ sólo tiene que "escanear" el entorno del _critter_, comenzando por su lado izquierdo y en sentido horario hasta encontrar un cuadrado vacío. Entonces se mueve en la dirección de ese cuadrado vacío. -What complicates things is that a critter may end up in the middle of -empty space, either as its start position or as a result of walking -around another critter. If we apply the approach I just described in -empty space, the poor critter will just keep on turning left at every -step, running in circles. +Lo que complica las cosas es que un _critter_ puede terminar en el medio del espacio vacío, ya sea como su posición inicial o como resultado de caminar alrededor de otro _critter_. Si aplicamos el enfoque que acabo de describir en el espacio vacío, el pobre _critter_ seguirá girando a la izquierda en cada paso, corriendo en círculos. -So there is an extra check (the `if` statement) to start scanning to -the left only if it looks like the critter has just passed some kind -of ((obstacle))—that is, if the space behind and to the left of the -critter is not empty. Otherwise, the critter starts scanning directly -ahead, so that it'll walk straight when in empty space. +De modo que hay una comprobación extra (la sentencia _if_) para iniciar el escaneado hacia la izquierda sólo si parece que el _critter_ acaba de pasar algún tipo de obstáculo, es decir, si el espacio detrás y hacia la izquierda del _critter_ no está vacío. De lo contrario, el _critter_ comienza a escanear directamente delante, de modo que va a caminar recto en el espacio vacío. -(((infinite loop)))And finally, there's a test comparing `this.dir` to -`start` after every pass through the loop to make sure that the loop -won't run forever when the critter is walled in or crowded in by other -critters and can't find an empty square. +(((infinite loop)))Y finalmente, hay una prueba que compara _this.dir_ con _start_ después de cada paso a través del _loop_ para cerciorarse de que el _loop_ no funcionará para siempre cuando el _critter_ está amurallado adentro o apretado adentro por otros _critters_ y no puede encontrar un cuadrado vacío. ifdef::interactive_target[] -This small world demonstrates the wall-following creatures: +Este pequeño mundo muestra las criaturas que siguen la pared: // test: no @@ -762,35 +549,17 @@ animateWorld(new World( endif::interactive_target[] -== A more lifelike simulation == - -(((simulation)))(((electronic life)))To make life in our world -more interesting, we will add the concepts of ((food)) and -((reproduction)). Each living thing in the world gets a new property, -`energy`, which is reduced by performing actions and increased by -eating things. When the critter has enough ((energy)), it can -reproduce, generating a new critter of the same kind. To keep things -simple, the critters in our world reproduce asexually, all by -themselves. - -(((energy)))(((entropy)))If critters only move around and eat one -another, the world will soon succumb to the law of increasing entropy, -run out of energy, and become a lifeless wasteland. To prevent this -from happening (too quickly, at least), we add ((plant))s to the -world. Plants do not move. They just use ((photosynthesis)) to grow -(that is, increase their energy) and reproduce. - -(((World type)))To make this work, we'll need a world with a different -`letAct` method. We could just replace the method of the `World` -prototype, but I've become very attached to our simulation with the -wall-following critters and would hate to break that old world. - -(((actionTypes object)))(((LifeLikeWorld type)))One solution is to use -((inheritance)). We create a new ((constructor)), `LifelikeWorld`, -whose prototype is based on the `World` prototype but which overrides -the `letAct` method. The new `letAct` method delegates the work of -actually performing an action to various functions stored in the -`actionTypes` object. +== Una simulación más realista == + +(((simulation)))(((electronic life)))Para hacer la vida en nuestro mundo más interesante, vamos a añadir los conceptos de la comida y la reproducción. Cada ser vivo en el mundo recibe una nueva propiedad, la energía, que se reduce mediante la realización de acciones y el aumento de comer cosas. Cuando la criatura tiene suficiente energía, puede reproducirse, generando una nueva criatura del mismo tipo. Para mantener las cosas simples, las criaturas en nuestro mundo se reproducen asexualmente por sí solas. + +Si los bichos sólo se mueven y comen unos a otros, el mundo pronto sucumbirá a la ley de entropía creciente, se quedará sin energía, y se convertirá en un desierto sin vida. Para evitar que esto suceda (demasiado rápido, al menos), añadimos plantas al mundo. Las plantas no se mueven. Simplemente utilizan la fotosíntesis para crecer (es decir, aumentar su energía) y reproducirse. + +(((World type)))Para que esto funcione, necesitaremos un mundo con un método _letAct_ diferente. Podríamos simplemente reemplazar el método del (prototipo _world_), pero me he vuelto muy apegado a nuestra simulación con las criaturas que siguen a la pared y odiaría romper ese viejo mundo. + + +(((actionTypes object)))(((LifeLikeWorld type)))Una solución es usar la (herencia). Creamos un nuevo (constructor), _LifelikeWorld_, cuyo prototipo se basa en el (prototipo World) pero que anula el método _letAct_. El nuevo método _letAct_ delega el trabajo de realizar una acción a varias funciones almacenadas en el objeto _actionTypes_. + // include_code @@ -817,24 +586,14 @@ LifelikeWorld.prototype.letAct = function(critter, vector) { }; ---- -(((electronic life)))(((function,as value)))(((call -method)))(((this)))The new `letAct` method first checks whether an -action was returned at all, then whether a handler function for this -type of action exists, and finally whether that handler returned -true, indicating that it successfully handled the action. Note the use -of `call` to give the handler access to the world, through its `this` -binding. +(((electronic life)))(((function,as value)))(((call method)))(((this)))El nuevo método _letAct_ comprueba primero si se ha devuelto una acción, si existe una (función de controlador) para este tipo de acción y, por último, si ese controlador devuelve _true_, lo que indica que se ha tratado correctamente la acción. -If the action didn't work for whatever reason, the default action is -for the creature to simply wait. It loses one-fifth point of ((energy)), -and if its energy level drops to zero or below, the creature dies and -is removed from the grid. +Tenga en cuenta el uso de _call_ para dar al manejador acceso al mundo a través de _this_. +Si la acción no funcionó por alguna razón, la acción predeterminada es que la criatura simplemente espere. Pierde un quinto punto de energía, y si su nivel de energía es igual o menor que cero, la criatura muere y se borra de la cuadrícula. -== Action handlers == +== Manejadores de acciones == -(((photosynthesis)))The simplest action a creature can perform is -`"grow"`, used by ((plant))s. When an action object like `{type: -"grow"}` is returned, the following handler method will be called: +(((photosynthesis)))La acción más simple que una criatura puede realizar es "crecer" (_grow_), usada por las plantas. Cuando se devuelve un objeto de acción como _{type: "grow"}_, se llamará al siguiente método del controlador: // include_code @@ -846,10 +605,8 @@ actionTypes.grow = function(critter) { }; ---- -Growing always succeeds and adds half a point to the plant's -((energy)) level. - -Moving is more involved. +Crecer siempre tiene éxito y añade medio punto al nivel de energía (_energy_) de la planta. +Moverse es más complicado. // include_code @@ -868,14 +625,9 @@ actionTypes.move = function(critter, vector, action) { }; ---- -(((validation)))This action first checks, using the `checkDestination` -method defined link:07_elife.html#checkDestination[earlier], whether -the action provides a valid destination. If not, or if the -destination isn't empty, or if the critter lacks the required -((energy)), `move` returns false to indicate no action was taken. -Otherwise, it moves the critter and subtracts the energy cost. +(((validation)))Esta acción comprueba primero, utilizando el método _checkDestination_ definido anteriormente, si la acción proporciona un destino válido. Si no, o si el destino no está vacío, o si el _critter_ carece de la energía requerida, _move_ devuelve false para indicar que no se tomó ninguna acción. De lo contrario, se mueve el _critter_ y resta el costo de la energía. -(((food)))In addition to moving, critters can eat. +(((food)))Además de moverse, las criaturas pueden comer. // include_code @@ -892,13 +644,9 @@ actionTypes.eat = function(critter, vector, action) { }; ---- -(((validation)))Eating another ((critter)) also involves providing a -valid destination square. This time, the destination must not be -empty and must contain something with ((energy)), like a critter (but -not a wall—walls are not edible). If so, the energy from the eaten is -transferred to the eater, and the victim is removed from the grid. +(((validation)))Comer otra criatura (_critter_) también implica proporcionar un cuadrado de destino válido. Esta vez, el destino no debe estar vacío y debe contener algo con energía, como un _critter_ (pero no una pared - las paredes no son comestibles). Si es así, la energía de la comida es transferida al comedor, y la víctima es removida de la cuadrícula. -(((reproduction)))And finally, we allow our critters to reproduce. +(((reproduction)))Y finalmente, permitimos que nuestras criaturas se reproduzcan. // include_code @@ -918,23 +666,13 @@ actionTypes.reproduce = function(critter, vector, action) { }; ---- -(((electronic life)))Reproducing costs twice the ((energy)) -level of the newborn critter. So we first create a (hypothetical) baby -using `elementFromChar` on the critter's own origin character. Once we -have a baby, we can find its energy level and test whether the parent -has enough energy to successfully bring it into the world. We also -require a valid (and empty) destination. +(((electronic life)))Reproducirse cuesta dos veces el nivel de energía de un _critter_ recién nacido. Así que primero creamos un bebé (hipotético) usando _elementFromChar_ en el propio carácter de origen del _critter_. Una vez que tenemos un bebé, podemos encontrar su nivel de energía y probar si el padre tiene suficiente energía para llevarlo con éxito al mundo. También necesitamos un destino válido (y vacío). -(((reproduction)))If everything is okay, the baby is put onto the grid -(it is now no longer hypothetical), and the energy is spent. +(((reproduction)))Si todo está bien, el bebé es puesto en la cuadrícula (ya no es hipotético), y la energía se gasta. -== Populating the new world == +== Llenar el nuevo mundo == -(((Plant type)))(((electronic life)))We now have a -((framework)) to simulate these more lifelike creatures. We could put -the critters from the old world into it, but they would just die -since they don't have an ((energy)) property. So let's make new ones. -First we'll write a ((plant)), which is a rather simple life-form. +(((Plant type)))(((electronic life)))Ahora tenemos un marco (_framework_) para simular estas criaturas en forma más realista. Podríamos poner las criaturas del viejo mundo en ella, pero sólo morirían ya que no tienen una propiedad de energía. Así que hagamos nuevos. Primero escribiremos una planta (_Plant_), que es una forma de vida bastante simple. // include_code @@ -943,9 +681,9 @@ First we'll write a ((plant)), which is a rather simple life-form. function Plant() { this.energy = 3 + Math.random() * 4; } -Plant.prototype.act = function(context) { +Plant.prototype.act = function(view) { if (this.energy > 15) { - var space = context.find(" "); + var space = view.find(" "); if (space) return {type: "reproduce", direction: space}; } @@ -955,14 +693,9 @@ Plant.prototype.act = function(context) { ---- (((reproduction)))(((photosynthesis)))(((random -number)))(((Math.random function)))Plants start with an energy level -between 3 and 7, randomized so that they don't all reproduce in the -same turn. When a plant reaches 15 energy points and there is empty -space nearby, it reproduces into that empty space. If a plant can't -reproduce, it simply grows until it reaches energy level 20. +number)))(((Math.random function)))Las plantas comienzan con un nivel de energía entre 3 y 7, aleatorizado para que no se reproduzcan todos en el mismo turno (_turn_). Cuando una planta alcanza 15 puntos de energía y hay un espacio vacío cerca, se reproduce en ese espacio vacío. Si una planta no puede reproducirse, simplemente crece hasta alcanzar el nivel de energía 20. -(((critter)))(((PlantEater type)))(((herbivore)))(((food chain)))We -now define a plant eater. +(((critter)))(((PlantEater type)))(((herbivore)))(((food chain)))Ahora definimos un comedor de plantas (_PlantEater_). // include_code @@ -971,11 +704,11 @@ now define a plant eater. function PlantEater() { this.energy = 20; } -PlantEater.prototype.act = function(context) { - var space = context.find(" "); +PlantEater.prototype.act = function(view) { + var space = view.find(" "); if (this.energy > 60 && space) return {type: "reproduce", direction: space}; - var plant = context.find("*"); + var plant = view.find("*"); if (plant) return {type: "eat", direction: plant}; if (space) @@ -983,15 +716,11 @@ PlantEater.prototype.act = function(context) { }; ---- -We'll use the `*` character for ((plant))s, so that's what this -creature will look for when it searches for ((food)). +Usaremos el carácter _*_ para las plantas (_Plant_), así que eso es lo que esta criatura buscará cuando busque comida. -== Bringing it to life == +== Darle vida == -(((electronic life)))And that gives us enough elements to try -our new world. Imagine the following map as a grassy valley with a herd of -((herbivore))s in it, some boulders, and lush ((plant)) life -everywhere. +(((electronic life)))Y eso nos da suficientes elementos para probar nuestro nuevo mundo. Imagínese el siguiente mapa como un valle cubierto de hierba con una manada de herbívoros en ella, algunas rocas y una exuberante vegetación en todas partes. // include_code @@ -1016,7 +745,7 @@ var valley = new LifelikeWorld( ); ---- -(((animation)))(((simulation)))Let's see what happens if we run this. +(((animation)))(((simulation)))Veamos ver ocurre cuando ejecutamos este codigo. (!book These snapshots illustrate a typical run of this world.!) ifdef::interactive_target[] @@ -1033,6 +762,9 @@ endif::interactive_target[] ifdef::book_target[] +// include_code + +[source,javascript] ---- ############################ ############################ ##### ###### ##### ** ###### @@ -1076,39 +808,18 @@ ifdef::book_target[] endif::book_target[] -(((stability)))(((reproduction)))(((extinction)))(((starvation)))Most -of the time, the plants multiply and expand quite quickly, but then -the abundance of ((food)) causes a population explosion of the -((herbivore))s, who proceed to wipe out all or nearly all of the -((plant))s, resulting in a mass starvation of the critters. Sometimes, -the ((ecosystem)) recovers and another cycle starts. At other times, -one of the species dies out completely. If it's the herbivores, the -whole space will fill with plants. If it's the plants, the remaining -critters starve, and the valley becomes a desolate wasteland. Ah, the -cruelty of nature. +(((stability)))(((reproduction)))(((extinction)))(((starvation)))La mayoría de las veces, las plantas se multiplican y se expanden con bastante rapidez, pero luego la abundancia de alimentos causa una explosión poblacional de los herbívoros, que proceden a eliminar todas o casi todas las plantas, resultando en un hambre masiva de las criaturas. A veces, el ecosistema se recupera y comienza otro ciclo. En otras ocasiones, una de las especies muere completamente. Si son los herbívoros, todo el espacio se llenará de plantas. Si son las plantas, las criaturas restantes mueren de hambre, y el valle se convierte en una tierra baldía desolada. Ah, la crueldad de la naturaleza. -== Exercises == +== Ejercicios == -=== Artificial stupidity === +=== Estupidez artificial === (((artificial stupidity (exercise))))(((artificial -intelligence)))(((extinction)))Having the inhabitants of our world go -extinct after a few minutes is kind of depressing. To deal with this, -we could try to create a smarter plant eater. - -(((pathfinding)))(((reproduction)))(((food)))There are several obvious -problems with our herbivores. First, they are terribly greedy, -stuffing themselves with every plant they see until they have wiped -out the local plant life. Second, their randomized movement (recall -that the `view.find` method returns a random direction when multiple -directions match) causes them to stumble around ineffectively and -starve if there don't happen to be any plants nearby. And finally, -they breed very fast, which makes the cycles between abundance and -famine quite intense. - -Write a new critter type that tries to address one or more of these -points and substitute it for the old `PlantEater` type in the valley -world. See how it fares. Tweak it some more if necessary. +intelligence)))(((extinction)))Tener extinguidos a los habitantes de nuestro mundo después de unos minutos es algo deprimente. Para hacer frente a esto, podríamos tratar de crear un comedor de plantas más inteligente (_smarter plant eater_). + +(((pathfinding)))(((reproduction)))(((food)))Hay varios problemas obvios con nuestros herbívoros. En primer lugar, son terriblemente codiciosos, tragan cada planta que ven hasta que han borrado toda la vida vegetal. En segundo lugar, su movimiento al azar (recuerde que el método _view.find:_ devuelve una dirección al azar cuando coinciden varias direcciones) hace que tropiecen ineficazmente y mueren de hambre si no encuentran ninguna planta cerca. Y finalmente, se reproducen muy rápido, lo que hace que los ciclos entre la abundancia y el hambre sean bastante intensos. + +Crea un nuevo tipo de _critter_ intentando abordar uno o más de estos puntos y sustituyelo por el antiguo tipo _PlantEater_ en el mundo del valle. Haga algunos ajustes mas si lo ve necesario. ifdef::interactive_target[] @@ -1140,47 +851,24 @@ animateWorld(new LifelikeWorld( endif::interactive_target[] -!!hint!! +!!pista!! (((artificial stupidity (exercise))))(((artificial -intelligence)))(((behavior)))(((state)))The greediness problem can be -attacked in several ways. The critters could stop eating when they -reach a certain ((energy)) level. Or they could eat only every N turns (by -keeping a counter of the turns since their last meal in a property on -the creature object). Or, to make sure plants never go entirely -extinct, the animals could refuse to eat a ((plant)) unless they see -at least one other plant nearby (using the `findAll` method on the -view). A combination of these, or some entirely different strategy, -might also work. - -(((pathfinding)))(((wall following)))Making the critters move more -effectively could be done by stealing one of the movement strategies -from the critters in our old, energyless world. Both the bouncing -behavior and the wall-following behavior showed a much wider range of -movement than completely random staggering. - -(((reproduction)))(((stability)))Making creatures breed more slowly is -trivial. Just increase the minimum energy level at which they -reproduce. Of course, making the ecosystem more stable also makes it -more boring. If you have a handful of fat, immobile critters forever -munching on a sea of plants and never reproducing, that makes for a -very stable ecosystem. But no one wants to watch that. - -!!hint!! - -=== Predators === - -(((predators (exercise))))(((carnivore)))(((food chain)))Any serious -((ecosystem)) has a food chain longer than a single link. Write -another ((critter)) that survives by eating the ((herbivore)) critter. -You'll notice that ((stability)) is even harder to achieve now that there -are cycles at multiple levels. Try to find a strategy to make the -ecosystem run smoothly for at least a little while. - -(((Tiger type)))One thing that will help is to make the world bigger. -This way, local population booms or busts are less likely to wipe out -a species entirely, and there is space for the relatively large prey -population needed to sustain a small predator population. +intelligence)))(((behavior)))(((state)))El problema de la codicia puede ser atacado de varias maneras. Las criaturas podrían dejar de comer cuando alcanzan un cierto nivel de energía. O pueden comer sólo cada N vueltas (manteniendo un contador de las vueltas desde su última comida en una propiedad en el objeto de criatura). O, para asegurarse de que las plantas nunca se extingan por completo, los animales podrían negarse a comer una planta a menos que vean por lo menos una planta cercana (usando el método findAll en la vista). Una combinación de estos, o alguna estrategia totalmente diferente, también podría funcionar + +El problema de la codicia puede ser atacado de varias maneras. Las criaturas podrían dejar de comer cuando alcanzan un cierto nivel de energía (_energy_). O pueden comer sólo cada _N_ vueltas (manteniendo un contador de las vueltas desde su última comida en una propiedad en el objeto _critters_). O, para asegurarse de que las plantas nunca se extingan por completo, los animales podrían negarse a comer una planta a menos que vean por lo menos una planta cercana (usando el método _findAll_ en la vista). Una combinación de estos, o alguna estrategia totalmente diferente, también podría funcionar. + +(((pathfinding)))(((wall following)))Hacer que los bichos se muevan más eficazmente se podría hacer copiando una de las estrategias de movimiento de las criaturas en nuestro viejo mundo sin energías. Tanto el comportamiento de rebote (_bouncing_) como el comportamiento de seguimiento de la pared (_wall-following_) mostraron un rango de movimiento mucho más amplio que el escalonamiento completamente aleatorio. + +(((reproduction)))(((stability)))Hacer que las criaturas se reproduzcan más lentamente es trivial. Sólo aumentar el nivel mínimo de energía en la que se reproducen. Por supuesto, hacer el ecosistema más estable también lo hace más aburrido. Si tienes un puñado de criaturas gordas e inmóviles reproducirse pero siempre comiendo en un mar de plantas, tienes un ecosistema muy estable, pero muy aburrido. + +!!pista!! + +=== Depredadores === + +(((predators (exercise))))(((carnivore)))(((food chain)))Cualquier ecosistema serio tiene una cadena alimentaria más larga que un solo eslabón. Escriba otro _critter_ que sobreviva comiendose al _critter_ herbívoro. Usted notará que la estabilidad es aún más difícil de lograr ahora que hay ciclos en múltiples niveles. Trate de encontrar una estrategia para hacer que el ecosistema funcione sin problemas durante al menos un tiempo. + +(((Tiger type)))Una cosa que ayudará es hacer el mundo más grande. De esta manera, los auges o bajas de la población local son menos propensos a eliminar completamente una especie, y hay espacio para la población de presas relativamente grande que se necesita para mantener una pequeña población de depredadores. ifdef::interactive_target[] @@ -1219,22 +907,10 @@ animateWorld(new LifelikeWorld( endif::interactive_target[] -!!hint!! - -(((predators (exercise))))(((reproduction)))(((starvation)))Many of -the same tricks that worked for the previous exercise also apply here. -Making the predators big (lots of energy) and having them reproduce -slowly is recommended. That'll make them less vulnerable to periods of -starvation when the herbivores are scarce. - -Beyond staying alive, keeping its ((food)) stock alive is a -predator's main objective. Find some way to make predators hunt -more aggressively when there are a lot of ((herbivore))s and hunt more -slowly (or not at all) when prey is rare. Since plant eaters move -around, the simple trick of eating one only when others are nearby is -unlikely to work—that'll happen so rarely that your predator will -starve. But you could keep track of observations in previous turns, in -some ((data structure)) kept on the predator objects, and have it base -its ((behavior)) on what it has seen recently. - -!!hint!! +!!pista!! + +(((predators (exercise))))(((reproduction)))(((starvation)))Muchos de los mismos trucos que trabajaron para el ejercicio anterior también se aplican aquí. Se recomienda hacer que los depredadores sean grandes (mucha energía) y que se reproduzcan lentamente. Eso los hará menos vulnerables a los períodos de hambre cuando los herbívoros son escasos. + +Más allá de mantenerse vivo, mantener vivo su alimento es el principal objetivo de un depredador. Encuentre alguna manera de hacer que los depredadores cazan de manera más agresiva cuando hay muchos herbívoros y cazan más lentamente (o no) cuando la presa es rara. Dado que los comedores de plantas se mueven, el simple truco de comer uno solo cuando otros están cerca no es probable que funcione, eso sucederá tan rara vez que su depredador se muera de hambre. Pero usted podría seguir la pista de observaciones en vueltas anteriores, en una cierta estructura de datos guardada en los objetos del depredador, y tenerla basar su comportamiento (_behavior_) en lo que ha visto recientemente. + +!!pista!! \ No newline at end of file diff --git a/08_error.txt b/08_error.txt index 7f6ecb411..a026b1ac6 100644 --- a/08_error.txt +++ b/08_error.txt @@ -3,15 +3,12 @@ :next_link: 09_regexp :load_files: ["code/chapter/08_error.js"] -= Bugs and Error Handling = += Bugs y manejo de errores = [chapterquote="true"] [quote, Brian Kernighan and P.J. Plauger, The Elements of Programming Style] ____ -Debugging is -twice as hard as writing the code in the first place. Therefore, if -you write the code as cleverly as possible, you are, by definition, -not smart enough to debug it. +La depuración es dos veces más difícil que escribir código. Por lo tanto, si usted escribe su código lo mejor que puede, por definición, usted no es lo suficientemente inteligente como para depurar lo que escribió. ____ ifdef::interactive_target[] @@ -19,76 +16,34 @@ ifdef::interactive_target[] [chapterquote="true"] [quote, Master Yuan-Ma, The Book of Programming] ____ -Yuan-Ma had written a small program that used many global variables -and shoddy shortcuts. Reading it, a student asked, ‘You warned us -against these techniques, yet I find them in your program. How can -this be?’ The master said, ‘There is no need to fetch a water hose -when the house is not on fire.’ +Yuan-Ma había escrito un pequeño programa que usaba muchas variables globales y atajos de mala calidad. Al leerlo, un estudiante le preguntó: 'Nos advirtió contra estas técnicas, sin embargo usted las usa en su programa. ¿Cómo puede ser? "El maestro respondió:" No hay necesidad de buscar una manguera de agua si la casa no está en llamas ". ____ endif::interactive_target[] -(((Kernighan+++,+++ Brian)))(((Plaugher+++,+++ P.J.)))(((debugging)))(((error handling)))A program is crystallized thought. -Sometimes those thoughts are confused. Other times, mistakes are -introduced when converting thought into code. Either way, the result -is a flawed program. +(((Kernighan+++,+++ Brian)))(((Plaugher+++,+++ P.J.)))(((debugging)))(((error handling)))Un programa es un pensamiento cristalizado. A veces son pensamientos con errores, otras veces los errores se producen al convertir nuestros pensamientos en código. De cualquier manera, el resultado es un programa defectuoso. -(((input)))(((output)))Flaws in a program are usually called ((bug))s. -Bugs can be programmer errors or problems in other systems that the -program interacts with. Some bugs are immediately apparent, while -others are subtle and might remain hidden in a system for years. +(((input)))(((output)))Las fallas en un programa se llaman generalmente _bugs_. Los _bugs_ pueden ser errores de programación o problemas en otros sistemas con los que nuestro programa interactúa. Algunos son inmediatamente evidentes, mientras que otros son sutiles y pueden permanecer ocultos en un sistema durante años. -Often, problems surface only when a program encounters a situation -that the programmer didn't originally consider. Sometimes such -situations are unavoidable. When the user is asked to input their age -and types _orange_, this puts our program in a difficult position. The -situation has to be anticipated and handled somehow. +A menudo, los problemas solamente surgen cuando un programa encuentra una situación que el programador no consideró originalmente. A veces tales situaciones son inevitables. Cuando se le pide al usuario que ingrese su edad (“_your age_”) y este tipea naranja (_“orange”_), esto pone a nuestro programa a prueba. Está situación tiene que ser anticipada y manejada de alguna manera. -== Programmer mistakes == +== Errores de programación == -(((parsing)))(((analysis)))When it comes to programmer mistakes, our -aim is simple. We want to find them and fix them. Such mistakes can -range from simple ((typo))s that cause the computer to complain as -soon as it lays eyes on our program to subtle mistakes in our -understanding of the way the program operates, causing incorrect -outcomes only in specific situations. Bugs of the latter type can -take weeks to diagnose. +(((parsing)))(((analysis)))Cuando se trata de errores del programador, nuestro tarea es simple: encontrarlos y arreglarlos. Tales errores pueden ir desde simples errores de tipeo, que causan que la computadora nos avice tan pronto como pone los ojos en nuestro programa, a errores sutiles a nuestra comprensión de la forma en que el programa opera, causando resultados incorrectos sólo en situaciones específicas. Los errores de este último tipo pueden tomar semanas para manifestarse. (((programming language)))(((type)))(((static typing)))(((dynamic -typing)))(((run-time error)))(((error)))The degree to which languages -help you find such mistakes varies. Unsurprisingly, JavaScript is at -the “hardly helps at all” end of that scale. Some languages want to -know the types of all your variables and expressions before even -running a program and will tell you right away when a type is used in -an inconsistent way. JavaScript considers types only when actually -running the program, and even then, it allows you to do some clearly -nonsensical things without complaint, such as `x = true * "monkey"`. - -(((syntax)))There are some things that JavaScript does complain about, -though. Writing a program that is not syntactically valid will -immediately trigger an error. Other things, such as calling something -that's not a function or looking up a ((property)) on an ((undefined)) -value, will cause an error to be reported when the program is running -and encounters the nonsensical action. - -(((NaN)))(((error)))But often, your nonsense computation will simply -produce a `NaN` (not a number) or undefined value. And the program -happily continues, convinced that it's doing something meaningful. The -mistake will manifest itself only later, after the bogus value has -traveled though several functions. It might not trigger an error at -all but silently cause the program's output to be wrong. Finding the -source of such problems can be difficult. - -(((debugging)))The process of finding mistakes—bugs—in programs is -called _debugging_. - -== Strict mode == +typing)))(((run-time error)))(((error)))El grado en que los lenguajes le ayudan a encontrar tales errores varía. No es sorprendente que JavaScript esté en el extremo de (("apenas ayuda")) de esa escala. Algunos lenguajes quieren saber los tipos de todas sus variables y expresiones antes incluso de ejecutar un programa y le dirán de inmediato cuando un tipo se utiliza de una manera inconsistente. JavaScript considera los tipos sólo cuando realmente ejecuta el programa, e incluso entonces, le permite hacer algunas cosas claramente absurdas sin quejarse, como _x = true * "monkey"_. + +(((syntax)))Sí hay algunas cosas que JavaScript no permite hacer. Escribir un programa que no es sintácticamente válido inmediatamente provocará un error. Otras cosas, como llamar a algo que no es una función o buscar una propiedad en un valor indefinido, provocará que se informe un error cuando el programa se está ejecutando y encuentra dicha acción sin sentido. + +(((NaN)))(((error)))Pero muchas veces, un cálculo sin sentido simplemente producirá un _NaN_ (no un número) o _undefined_ (valor indefinido). Y el programa continúa feliz, convencido de que está haciendo algo significativo. El error se manifestará sólo más tarde, después de que el valor falso haya recorrido varias funciones. No desencadena un error, pero en silencio hace que el resultado del programa sea incorrecto. Encontrar la fuente de tales problemas puede ser difícil. + +(((debugging)))El proceso de encontrar errores (_bugs_) en los programas se llama depuración (_debugging_). + +== Modo estricto (_Strict mode_) == indexsee:[use strict,strict mode] -(((strict mode)))(((syntax)))(((function)))JavaScript can be made a -_little_ more strict by enabling _strict mode_. This is done by -putting the string `"use strict"` at the top of a file or a function -body. Here's an example: +(((strict mode)))(((syntax)))(((function)))JavaScript se puede hacer un poco más estricto al permitir el modo estricto. Esto se hace poniendo la cadena "_use strict_" en la parte superior de un archivo o en el cuerpo de función. He aquí un ejemplo: // test: error "ReferenceError: counter is not defined" @@ -104,26 +59,11 @@ canYouSpotTheProblem(); // → ReferenceError: counter is not defined ---- -(((var keyword)))(((variable,global)))Normally, when you forget to put -`var` in front of your variable, as with `counter` in the example, -JavaScript quietly creates a global variable and uses that. In strict -mode, however, an ((error)) is reported instead. This is very helpful. -It should be noted, though, that this doesn't work when the variable -in question already exists as a global variable, but only when -assigning to it would have created it. +(((var keyword)))(((variable,global)))Normalmente, cuando te olvidas de poner _var_ delante de tu variable, como _counter_ en el ejemplo, JavaScript crea una variable global en silencio y usa eso. En el modo estricto, sin embargo, un error se informa en su lugar. Esto es muy útil. Debe tenerse en cuenta, sin embargo, que esto no funciona cuando la variable en cuestión ya existe como global, sólo funciona cuando no existe y la asignación que hemos hecho la habría creado. -(((this)))(((global object)))(((undefined)))(((strict mode)))Another -change in strict mode is that the `this` binding holds the value -`undefined` in functions that are not called as ((method))s. When -making such a call outside of strict mode, `this` refers to the global -scope object. So if you accidentally call a method or constructor -incorrectly in strict mode, JavaScript will produce an error as soon -as it tries to read something from `this`, rather than happily working -with the global object, creating and reading global variables. +(((this)))(((global object)))(((undefined)))(((strict mode)))Otro cambio en modo estricto es que _this_ mantiene el valor _undefined_ en funciones que no se llaman como métodos. Al hacer una llamada fuera del modo estricto, _this_ se refiere al objeto de alcance global. Así que si accidentalmente llama a un método o constructor incorrectamente en modo estricto, JavaScript producirá un error tan pronto como intente leer algo de esto, en lugar de trabajar felizmente con el objeto global, crear y leer variables globales. -For example, consider the following code, which calls a -((constructor)) without the `new` keyword so that its `this` will -_not_ refer to a newly constructed object: +Por ejemplo, considere el siguiente código, que llama a un _constructor_ sin la palabra clave _new_, de modo que _this_ no se refiere al objeto recien construído: [source,javascript] ---- @@ -133,9 +73,7 @@ console.log(name); // → Ferdinand ---- -(((error)))So the bogus call to `Person` succeeded but returned an -undefined value and created the global variable `name`. In strict -mode, the result is different. +(((error)))Así que la llamada falsa a _Person_ tuvo éxito pero devolvió un valor _undefined_ y creó el nombre de la variable en forma global. En modo estricto, el resultado es diferente. // test: error "TypeError: Cannot set property 'name' of undefined" @@ -148,28 +86,19 @@ var ferdinand = Person("Ferdinand"); // → TypeError: Cannot set property 'name' of undefined ---- -We are immediately told that something is wrong. This is helpful. +Nos dice inmediatamente que algo está mal. Esto es muy útil. -(((parameter)))(((variable,naming)))(((with statement)))Strict mode -does a few more things. It disallows giving a function multiple -parameters with the same name and removes certain problematic -language features entirely (such as the `with` statement, which is so -misguided it is not further discussed in this book). +(((parameter)))(((variable,naming)))(((with statement)))El modo estricto (_Strict mode_) hace algunas cosas más: Se prohíbe dar a una función múltiples parámetros con el mismo nombre y elimina completamente ciertas características problemáticas del lenguaje (como la declaración _which_, que es tan equivocada que no volveré a mencionarla en este libro). -(((debugging)))In short, putting a `"use strict"` at the top of your -program rarely hurts and might help you spot a problem. +(((debugging)))En pocas palabras, poner un _use strict_ en la parte superior de su programa rara vez causa daño y puede ayudarle a detectar un problema. -== Testing == +== _Tests_ == -(((test suite)))(((run-time error)))If the language is not going to do -much to help us find mistakes, we'll have to find them the hard way: -by running the program and seeing whether it does the right thing. +(((test suite)))(((run-time error)))Si el lenguaje no va a hacer mucho para ayudarnos a encontrar errores, tendremos que encontrarlos de la manera más difícil: ejecutando el programa y ver si hace lo correcto. -Doing this by hand, again and again, is a sure way to drive yourself -insane. Fortunately, it is often possible to write a second program -that automates testing your actual program. +Hacer esto a mano, una y otra vez, es una manera segura de volverse loco. Afortunadamente, a menudo es posible escribir un segundo programa que automatice las pruebas de su programa. -(((Vector type)))As an example, we once again use the `Vector` type. +(((Vector type)))Como ejemplo, volvemos a utilizar el tipo _Vector_. // include_code @@ -184,12 +113,7 @@ Vector.prototype.plus = function(other) { }; ---- -We will write a program to check that our implementation of `Vector` -works as intended. Then, every time we change the implementation, we -follow up by running the test program so that we can be reasonably -confident that we didn't break anything. When we add extra -functionality (for example, a new method) to the `Vector` type, we also -add tests for the new feature. +Escribiremos un programa para comprobar que nuestra implementación de _Vector_ funciona como se pretende. Luego, cada vez que cambiamos la implementación, seguimos ejecutando el programa de prueba para que podamos estar razonablemente seguros de que no rompimos nada. Cuando agregamos funcionalidad adicional (por ejemplo, un nuevo método) al tipo _Vector_, también agregamos pruebas para la nueva característica. [source,javascript] ---- @@ -210,35 +134,17 @@ console.log(testVector()); ---- (((test suite)))(((testing framework)))(((domain-specific -language)))Writing tests like this tends to produce rather repetitive, -awkward code. Fortunately, there exist pieces of software that help -you build and run collections of tests (_test suites_) by providing a -language (in the form of functions and methods) suited to expressing -tests and by outputting informative information when a test fails. These -are called _testing frameworks_. - -== Debugging == - -(((debugging)))Once you notice that there is something wrong with your -program because it misbehaves or produces errors, the next step is to -figure out _what_ the problem is. - -Sometimes it is obvious. The ((error)) message will point at a -specific line of your program, and if you look at the error -description and that line of code, you can often see the problem. - -(((run-time error)))But not always. Sometimes the line that triggered -the problem is simply the first place where a bogus value produced -elsewhere gets used in an invalid way. And sometimes there is no error -message at all—just an invalid result. If you have been solving the -((exercises)) in the earlier chapters, you will probably have already -experienced such situations. - -(((decimal number)))(((binary number)))The following example program -tries to convert a whole number to a string in any base (decimal, -binary, and so on) by repeatedly picking out the last ((digit)) and then -dividing the number to get rid of this digit. But the insane output -that it currently produces suggests that it has a ((bug)). +language)))Escribir pruebas como ésta tiende a producir código bastante repetitivo, incómodo. Afortunadamente, existen piezas de software que ayudan a crear y ejecutar conjuntos de pruebas (_test suites_) proporcionando un lenguaje (en forma de funciones y métodos) adecuado para expresar las pruebas y para emitir información puntual cuando una prueba falla. Estos se llaman _testing frameworks_. + +== _Debugging_ == + +(((debugging)))Una vez que usted nota que hay algo mal con su programa porque se comporta mal o produce errores, el siguiente paso es averiguar cuál es el problema. + +A veces es obvio. El mensaje de error apuntará en una línea específica de su programa y si observa la descripción del error y esa línea de código, a menudo puede ver el problema. + +(((run-time error)))Pero no siempre. A veces la línea que desencadenó el problema es simplemente el primer lugar donde se utiliza de manera no válida un valor erroneo que fue producido en otro lugar. Y a veces no hay ningún mensaje de error en absoluto, sólo un resultado no válido. Si ha estado resolviendo los ejercicios en los capítulos anteriores, es probable que ya haya experimentado tales situaciones. + +(((decimal number)))(((binary number)))El programa de ejemplo siguiente intenta convertir un número entero en una cadena en cualquier base (decimal, binario, etc.) seleccionando repetidamente el último dígito y luego dividiendo el número para eliminar este dígito. Pero la valor de retorno ridículo que produce actualmente sugiere que tiene un error (_bug_). [source,javascript] ---- @@ -258,22 +164,11 @@ console.log(numberToString(13, 10)); // → 1.5e-3231.3e-3221.3e-3211.3e-3201.3e-3191.3e-3181.3… ---- -(((analysis)))Even if you see the problem already, pretend for a -moment that you don't. We know that our program is malfunctioning, and -we want to find out why. +(((analysis)))Incluso si usted ya noto cual es el problema, finja por un momento que aun no lo a descubierto. Sabemos que nuestro programa está funcionando mal, y queremos averiguar por qué. -(((trial and error)))This is where you must resist the urge to start -making random changes to the code. Instead, _think_. Analyze what is -happening and come up with a ((theory)) of why it might be happening. -Then, make additional observations to test this theory—or, if you -don't yet have a theory, make additional observations that might help -you come up with one. +(((trial and error)))Aquí es donde debe resistir el impulso de comenzar a hacer cambios aleatorios en el código. Trate de analizar lo que está sucediendo y llegar a una teoría de por qué podría estar sucediendo. Luego, haga observaciones adicionales para probar esta teoría o, si aún no tiene una teoría, haga observaciones adicionales que podrían ayudarle a encontrar una. -(((console.log)))(((output)))(((debugging)))(((logging)))Putting a few -strategic `console.log` calls into the program is a good way to get -additional information about what the program is doing. In this case, -we want `n` to take the values `13`, `1`, and then `0`. Let's write -out its value at the start of the loop. +(((console.log)))(((output)))(((debugging)))(((logging)))Poner unas pocas llamadas _console.log_ estratégicas en el programa es una buena manera de obtener información adicional sobre lo que está haciendo el programa. En este caso, queremos que _n_ tome los valores _13_, _1_ y luego _0_. Vamos a escribir su valor al inicio del bucle. ---- 13 @@ -284,50 +179,22 @@ out its value at the start of the loop. 1.5e-323 ---- -(((rounding)))_Right_. Dividing 13 by 10 does not produce a whole -number. Instead of `n /= base`, what we actually want is `n = -Math.floor(n / base)` so that the number is properly “shifted” to the -right. +(((rounding)))_Right_. Dividir _13_ por _10_ no produce un número entero. En lugar de _n / = base_, lo que realmente queremos es _n = Math.floor (n / base)_ para que el número se desplace correctamente a la derecha. -(((JavaScript console)))(((breakpoint)))(((debugger statement)))An -alternative to using `console.log` is to use the _debugger_ -capabilities of your browser. Modern browsers come with the ability to -set a _breakpoint_ on a specific line of your code. This will cause -the execution of the program to pause every time the line with the -breakpoint is reached and allow you to inspect the values of -variables at that point. I won't go into details here since debuggers -differ from browser to browser, but look in your browser's developer -tools and search the Web for more information. Another way to set a -breakpoint is to include a `debugger` statement (consisting of simply -that keyword) in your program. If the ((developer tools)) of your -browser are active, the program will pause whenever it reaches that -statement, and you will be able to inspect its state. +(((JavaScript console)))(((breakpoint)))(((debugger statement)))Una alternativa al uso de _console.log_ es utilizar las capacidades de depuración de su navegador. Los navegadores modernos vienen con la capacidad de establecer un ((punto de interrupción)) en una línea específica de su código. Esto hará que la ejecución del programa se detenga cada vez que se alcanza la línea con el punto de interrupción y le permite inspeccionar los valores de las variables en ese punto. No entraré en detalles aquí ya que los depuradores difieren de navegador a navegador, pero busque en las herramientas de desarrollo de su navegador y busque en la Web más información. Otra forma de establecer un punto de interrupción es incluir una declaración de depurador (que consiste simplemente en la palabra clave _debugger_) en su programa. Si las herramientas de desarrollo de su navegador están activas, el programa se detendrá cada vez que llegue a esa declaración, y podrá inspeccionar su estado. -== Error propagation == +== Propagación de errores == (((input)))(((output)))(((run-time -error)))(((error)))(((validation)))Not all problems can be prevented -by the programmer, unfortunately. If your program communicates with -the outside world in any way, there is a chance that the input it gets -will be invalid or that other systems that it tries to talk to are -broken or unreachable. - -(((error recovery)))Simple programs, or programs that run only under -your supervision, can afford to just give up when such a problem -occurs. You'll look into the problem and try again. “Real” -applications, on the other hand, are expected to not simply crash. -Sometimes the right thing to do is take the bad input in stride and -continue running. In other cases, it is better to report to the user -what went wrong and then give up. But in either situation, the program -has to actively do something in response to the problem. - -(((promptInteger function)))(((validation)))Say you have a function -`promptInteger` that asks the user for a whole number and returns it. -What should it return if the user inputs _orange_? +error)))(((error)))(((validation)))No todos los problemas pueden ser prevenidos por el programador. Si su programa se comunica con el mundo exterior de alguna manera, existe la posibilidad de que la entrada que obtenga sea inválida o que otros sistemas con los que intente hablar estén rotos o inaccesibles. + +(((error recovery)))Los programas sencillos, o programas que se ejecutan sólo bajo su supervisión, pueden permitirse el lujo de dejar de funcionar cuando se produce un problema de este tipo. Examinarás el problema y lo intentarás de nuevo. Pero las aplicaciones "reales" no se pueden simplemente desconectar. A veces lo correcto es tomar la entrada mala y seguir corriendo. En otros casos, es mejor informar al usuario de lo que salió mal y luego desconectar. Pero en cualquier situación, el programa tiene que hacer algo activamente en respuesta al problema. + +(((promptInteger function)))(((validation)))Digamos que tiene una función _promptInteger_ que pide al usuario un número entero y lo devuelve. +Pero ¿Qué debe devolver si el usuario ingresa una palabra, por ejemplo confunde "_your age_" por “_orange_”? (((null)))(((undefined)))(((return value)))(((special return -value)))One option is to make it return a special value. Common -choices for such values are `null` and `undefined`. +value)))Una opción es hacer que devuelva un valor especial. Las opciones comunes para estos valores son _null_ y no _undefined_. // test: no @@ -342,55 +209,22 @@ function promptNumber(question) { console.log(promptNumber("How many trees do you see?")); ---- -This is a sound strategy. Now any code that calls `promptNumber` must -check whether an actual number was read and, failing that, must -somehow recover—maybe by asking again or by filling in a default -value. Or it could again return a special value to _its_ caller to -indicate that it failed to do what it was asked. +Esta es una buena estrategia. Ahora cualquier código que llama a _promptNumber_ debe comprobar si se ha leído un número real y, de no ser así, debe reiniciar el proceso de alguna manera, tal vez preguntando de nuevo o rellenando con un valor predeterminado. O podría devolver un valor especial a su llamador (_caller_) para indicar que no pudo hacer lo que se le pidió. -(((error handling)))In many situations, mostly when ((error))s are -common and the caller should be explicitly taking them into account, -returning a special value is a perfectly fine way to indicate an -error. It does, however, have its downsides. First, what if the -function can already return every possible kind of value? For such a -function, it is hard to find a special value that can be distinguished -from a valid result. +(((error handling)))En muchas situaciones, sobre todo cuando los errores son comunes y el metodo _caller_ debe tenerlo explícitamente en cuenta, devolver un valor especial es una manera prolija de indicar un error. Sin embargo, tiene sus desventajas. Primero, ¿qué pasa si la función ya puede devolver todo tipo posible de valores? Para esta función, es difícil encontrar un valor especial que pueda distinguirse de un resultado válido. -(((special return value)))(((readability)))The second issue with -returning special values is that it can lead to some very cluttered -code. If a piece of code calls `promptNumber` 10 times, it has to -check 10 times whether `null` was returned. And if its response to -finding `null` is to simply return `null` itself, the caller will in -turn have to check for it, and so on. +(((special return value)))(((readability)))La segunda cuestión con la devolución de valores especiales es que puede conducir a algún código muy abarrotado. Si un pedazo de código llama a _promptNumber_ 10 veces, tiene que comprobar 10 veces si se devolvió _null_. Y si su respuesta a encontrar _null_ es simplemente devolver _null_ a sí mismo, el llamador (_caller_) a su vez tendrá que comprobarlo, y así sucesivamente. -== Exceptions == +== Excepciones == -(((error handling)))When a function cannot proceed normally, what we -would _like_ to do is just stop what we are doing and immediately jump -back to a place that knows how to handle the problem. This is what -_((exception handling))_ does. +(((error handling)))Cuando una función no puede proceder normalmente, lo que nos gustaría hacer es simplemente detener lo que estamos haciendo y trabajar en un contexto donde sabemos cómo manejar el problema. Esto es el “manejo de excepciones”. (((control flow)))(((raising (exception))))(((throw keyword)))(((call -stack)))Exceptions are a mechanism that make it possible for code that -runs into a problem to _raise_ (or _throw_) an exception, which is -simply a value. Raising an exception somewhat resembles a -super-charged return from a function: it jumps out of not just the -current function but also out of its callers, all the way down to the -first call that started the current execution. This is called -_((unwinding the stack))_. You may remember the stack of function -calls that was mentioned in link:03_functions.html#stack[Chapter 3]. -An exception zooms down this stack, throwing away all the call -contexts it encounters. - -(((error handling)))(((syntax)))(((catch keyword)))If exceptions -always zoomed right down to the bottom of the stack, they would not be -of much use. They would just provide a novel way to blow up your -program. Their power lies in the fact that you can set “obstacles” -along the stack to _catch_ the exception as it is zooming down. Then -you can do something with it, after which the program continues -running at the point where the exception was caught. - -Here's an example: +stack)))Las excepciones (_exceptions_) son un mecanismo que hace posible que el código que se ejecuta en un problema lance (_throw_) una excepción, que es simplemente lanzar un valor. Elevar una excepción se asemeja en cierta medida a un retorno súper cargado de una función: se eleva no sólo de la función actual, sino también de sus llamantes, hasta la primera llamada que inició la ejecución actual. Esto se llama desenrollar la pila (_unwinding the stack_). Recuerde el concepto de “pila de llamadas de función” en el link:03_functions.html#stack[Capítulo 3]. Una excepción reduce el zoom de esta pila, eliminando todos los contextos de llamada que encuentra. + +(((error handling)))(((syntax)))(((catch keyword)))Si las excepciones siempre estan cerca de la parte inferior de la pila, no serían de mucha utilidad, pues sólo proporcionaría una nueva manera de lanzar su programa. Su poder reside en el hecho de que usted puede establecer "obstáculos" a lo largo de la pila para capturar la excepción. Entonces usted puede actuar, después de que el programa continúa funcionando en el punto donde registró la excepción. + +He aquí un ejemplo: [[look]] [source,javascript] @@ -417,41 +251,18 @@ try { ---- (((exception handling)))(((block)))(((throw keyword)))(((try -keyword)))(((catch keyword)))The `throw` keyword is used to raise an -exception. Catching one is done by wrapping a piece of code in a `try` -block, followed by the keyword `catch`. When the code in the `try` -block causes an exception to be raised, the `catch` block is -evaluated. The variable name (in parentheses) after `catch` will be -bound to the exception value. After the `catch` block finishes—or if -the `try` block finishes without problems—control proceeds beneath the -entire `try/catch` statement. +keyword)))(((catch keyword)))La palabra clave _throw_ se utiliza para generar una excepción. Capturar una se hace envolviendo (_wrapping_) un pedazo de código en un bloque _try_, seguido por la palabra clave _catch_. Cuando el código del bloque _try_ genera una excepción, se evalúa el bloque _catch_. El nombre de la variable (entre paréntesis) después de la captura se enlazará al valor de la excepción. Una vez finalizado el bloqueo del bloque (o si el bloque _try_ termina sin problemas), el control se desarrolla debajo de toda la sentencia _try_/_catch_. (((debugging)))(((call stack)))(((Error type)))(((stack -trace)))In this case, we used the `Error` ((constructor)) to create -our exception value. This is a ((standard)) JavaScript constructor -that creates an object with a `message` property. In modern JavaScript -environments, instances of this constructor also gather information -about the call stack that existed when the exception was created, a -so-called _stack trace_. This information is stored in the `stack` -property and can be helpful when trying to debug a problem: it -tells us the precise function where the problem occurred and which -other functions led up to the call that failed. - -(((exception handling)))Note that the function `look` completely -ignores the possibility that `promptDirection` might go wrong. This is -the big advantage of exceptions—error-handling code is necessary only -at the point where the error occurs and at the point where it is -handled. The functions in between can forget all about it. - -Well, almost... - -== Cleaning up after exceptions == +trace)))En este caso, utilizamos el constructor _Error_ para crear nuestro valor de excepción (_new Error_). . Se trata de un constructor de JavaScript estándar que crea un objeto con una propiedad de mensaje. En los entornos de JavaScript modernos, las instancias de este constructor también recopilan información sobre la pila de llamadas que existía cuando se creó la excepción, un denominado seguimiento de la pila (_stack trace_). Esta información se almacena en la propiedad de la pila y puede ser útil al intentar depurar un problema: nos indica la función exacta donde ocurrió el problema y cuáles otras funciones llevaron a la llamada que falló. + +(((exception handling)))Tenga en cuenta que en nuestro ejemplo la función _look_ ignora por completo la posibilidad de que _promptDirection_ pueda salir mal. Esta es la gran ventaja de las excepciones: el código de manejo de errores sólo es necesario en el punto donde se produce el error y en el punto donde se maneja. Las funciones intermedias pueden desentenderse de todo. +Bueno, casi... + +== Limpieza después de excepciones == (((exception handling)))(((cleaning up)))(((withContext -function)))(((dynamic scope)))Consider the following situation: a -function, `withContext`, wants to make sure that, during its -execution, the top-level variable `context` holds a specific context -value. After it finishes, it restores this variable to its old value. +function)))(((dynamic scope)))Considere la siguiente situación: una función, _withContext_, quiere asegurarse de que, durante su ejecución, la variable de nivel superior _context_ contiene un valor específico. Después de que termina, restaura esta variable a su valor anterior. // include_code @@ -468,17 +279,9 @@ function withContext(newContext, body) { } ---- -What if `body` raises an exception? In that case, the call to -`withContext` will be thrown off the stack by the exception, and -`context` will never be set back to its old value. +¿Qué pasa si _body_ plantea una excepción? En ese caso, la llamada a _withContext_ será eliminada de la pila por la excepción, y _context_ nunca volverá a su valor anterior. -(((block)))(((try keyword)))(((finally keyword)))There is one more -feature that `try` statements have. They may be followed by a -`finally` block either instead of or in addition to a `catch` -block. A `finally` block means “No matter _what_ happens, run this -code after trying to run the code in the `try` block”. If a function -has to clean something up, the cleanup code should usually be put into -a `finally` block. +(((block)))(((try keyword)))(((finally keyword)))Hay una característica más que tiene _try_. Puede ser seguida por un bloque _finally_ en lugar de, o además de, un bloque _catch_. Un bloque _finally_ dice "No importa lo que pase, ejecute este código después de intentar ejecutar el código en el bloque _try_". Si una función tiene que limpiar algo, el código de limpieza normalmente se debe poner en el bloque _finally_. // include_code @@ -495,10 +298,7 @@ function withContext(newContext, body) { } ---- -(((withContext function)))Note that we no longer have to store the -result of `body` (which we want to return) in a variable. Even if we -return directly from the `try` block, the `finally` block will be run. -Now we can do this and be safe: +(((withContext function)))Tenga en cuenta que ya no tenemos que almacenar el resultado del _body_ (que queremos devolver) en una variable. Incluso si regresamos directamente desde el bloque _try_, se ejecutará el bloque _finally_. Podemos hacerlo y estar seguros: // test: no @@ -518,51 +318,25 @@ console.log(context); // → null ---- -Even though the function called from `withContext` exploded, -`withContext` itself still properly cleaned up the `context` variable. +A pesar de que la función llamada por withContext explotó, en _withContext_ se limpió adecuadamente la variable _context_. == Selective catching == (((uncaught exception)))(((exception handling)))(((JavaScript -console)))(((developer tools)))(((call stack)))(((error)))When an -exception makes it all the way to the bottom of the stack without -being caught, it gets handled by the environment. What this means -differs between environments. In browsers, a description of the error -typically gets written to the JavaScript console (reachable through -the browser's Tools or Developer menu). - -(((crash)))(((error handling)))For programmer mistakes or problems -that the program cannot possibly handle, just letting the error go -through is often okay. An unhandled exception is a reasonable way to -signal a broken program, and the JavaScript console will, on modern -browsers, provide you with some information about which function calls -were on the stack when the problem occurred. - -(((user interface)))For problems that are _expected_ to happen during -routine use, crashing with an unhandled exception is not a very -friendly response. +console)))(((developer tools)))(((call stack)))(((error)))Cuando una excepción hace todo el camino a la parte inferior de la pila sin ser capturada, se maneja por el medio ambiente. Lo que esto significa difiere entre entornos. En los navegadores, normalmente se escribe una descripción del error en la consola de JavaScript (accesible a través del menú Herramientas o Desarrollador del navegador). + +(((crash)))(((error handling)))Para los errores o problemas del programador que el programa no puede manejar, simplemente dejar pasar el error es lo correcto a menudo. Una excepción no tratada es una forma razonable de señalar un programa roto, y la consola de JavaScript, en navegadores modernos, le proporcionará cierta información sobre qué llamadas de función estaban en la pila cuando ocurrió el problema. + +(((user interface)))Para los problemas que se espera que sucedan durante el uso rutinario, estrellarse con una excepción no tratada no es una respuesta amigable. (((syntax)))(((function,application)))(((exception handling)))(((Error -type)))Invalid uses of the language, such as referencing a nonexistent -((variable)), looking up a property on `null`, or calling something -that's not a function, will also result in exceptions being raised. -Such exceptions can be caught just like your own exceptions. - -(((catch keyword)))When a `catch` body is entered, all we know is that -_something_ in our `try` body caused an exception. But we don't know -_what_, or _which_ exception it caused. - -(((exception handling)))JavaScript (in a rather glaring omission) -doesn't provide direct support for selectively catching exceptions: -either you catch them all or you don't catch any. This makes it very -easy to _assume_ that the exception you get is the one you were -thinking about when you wrote the `catch` block. - -(((promptDirection function)))But it might not be. Some other -((assumption)) might be violated, or you might have introduced a bug -somewhere that is causing an exception. Here is an example, which -_attempts_ to keep on calling `promptDirection` until it gets a valid -answer: +type)))Los usos no válidos del lenguaje, como hacer referencia a una variable inexistente, buscar una propiedad en _null_ o llamar a algo que no es una función, también darán lugar a que se generen excepciones. Tales excepciones se pueden capturar igual que sus propias excepciones. + +(((catch keyword)))Cuando se introduce un _catch_, todo lo que sabemos es que algo en nuestro _try_ causó una excepción. Pero no sabemos qué, ni qué excepción causó. + +(((exception handling)))JavaScript (en una omisión bastante flagrante) no proporciona soporte directo para capturar selectivamente las excepciones: o bien las captura todas o no las captura. Esto hace que sea muy fácil asumir que la excepción que se obtiene es la misma que la que se estaba pensando cuando escribió el bloque _catch_. + +(((promptDirection function)))Pero puede que no lo sea. Es posible que se haya violado alguna otra suposición o que haya introducido un error en algún lugar que esté causando una excepción. He aquí un ejemplo, que intenta seguir llamando a _promptDirection_ hasta obtener una respuesta válida: // test: no @@ -579,35 +353,15 @@ for (;;) { } ---- -(((infinite loop)))(((for loop)))(((catch keyword)))(((debugging)))The -`for (;;)` construct is a way to intentionally create a loop that -doesn't terminate on its own. We break out of the loop only when a -valid direction is given. _But_ we misspelled `promptDirection`, -which will result in an “undefined variable” error. Because the -`catch` block completely ignores its exception value (`e`), assuming -it knows what the problem is, it wrongly treats the variable error as -indicating bad input. Not only does this cause an infinite loop, but -it also “buries” the useful error message about the misspelled -variable. - -As a general rule, don't blanket-catch exceptions unless it is for the -purpose of “routing” them somewhere—for example, over the network to -tell another system that our program crashed. And even then, think -carefully about how you might be hiding information. - -(((exception handling)))So we want to catch a _specific_ kind of -exception. We can do this by checking in the `catch` block whether the -exception we got is the one we are interested in and by rethrowing it -otherwise. But how do we recognize an exception? - -Of course, we could match its `message` property against the ((error)) -message we happen to expect. But that's a shaky way to write code—we'd -be using information that's intended for human consumption (the -message) to make a programmatic decision. As soon as someone changes -(or translates) the message, the code will stop working. - -(((Error type)))(((instanceof operator)))Rather, let's define a new -type of error and use `instanceof` to identify it. +(((infinite loop)))(((for loop)))(((catch keyword)))(((debugging)))El constructo _for (;;)_ es una forma de crear intencionalmente un bucle que no termina por sí solo. Salimos del bucle sólo cuando se da una dirección válida. Pero hemos escrito erróneamente promptDirection, lo que resultará en un error de "variable indefinida". Debido a que el bloque de _catch_ ignora completamente su valor de excepción (_e_), suponiendo que sabe cuál es el problema, trata erróneamente el error de variable como indicativo de entrada incorrecta. Esto no sólo causa un bucle infinito, sino que también "entierra" el útil mensaje de error sobre la variable mal escrita. + +AComo regla general, no cubra las excepciones de captura a menos que sea con el propósito de "enrutarlas" en alguna parte, por ejemplo, a través de la red para decirle a otro sistema que nuestro programa se ha estrellado. E incluso entonces, piense cuidadosamente en cómo podría estar ocultando información. + +(((exception handling)))Así que queremos capturar un tipo específico de excepción. Podemos hacer esto comprobando en el bloque _catch_ si la excepción que conseguimos es la que buscamos y probar de otra manera. Pero, ¿cómo reconocemos una excepción? + +Por supuesto, podríamos igualar su propiedad de mensaje con el mensaje de error que esperamos. Pero esa es una manera inestable de escribir código: usariamos la información destinada al consumo humano (el mensaje) para tomar una decisión programática. Tan pronto como alguien cambia (o traduce) el mensaje, el código dejará de funcionar. + +(((Error type)))(((instanceof operator)))Más bien, definamos un nuevo tipo de error y usamos _instanceof_ para identificarlo. // include_code @@ -621,19 +375,11 @@ InputError.prototype = Object.create(Error.prototype); InputError.prototype.name = "InputError"; ---- -(((throw keyword)))(((inheritance)))The prototype is made to derive -from `Error.prototype` so that `instanceof Error` will also return -true for `InputError` objects. It's also given a `name` property -since the standard error types (`Error`, `SyntaxError`, -`ReferenceError`, and so on) also have such a property. +(((throw keyword)))(((inheritance)))El prototipo se crea al derivar de _Error.prototype_ para que _instanceof Error_ también devuelva _true_ para los objetos _InputError_. También se le da una propiedad de nombre (_name_) ya que los tipos de error estándar (_Error_, _SyntaxError_, _ReferenceError_, etc.) también tienen dicha propiedad. -(((call stack)))The assignment to the `stack` property tries to give -this object a somewhat useful ((stack trace)), on platforms that -support it, by creating a regular error object and then using that -object's `stack` property as its own. +(((call stack)))La asignación a la propiedad _stack_ intenta dar a este objeto un rastreo de pila algo útil (en plataformas que lo soportan) creando un objeto de error regular y luego utilizando la propiedad _stack_ de ese objeto como propio. -(((promptDirection function)))Now `promptDirection` can throw such an -error. +(((promptDirection function)))Ahora _promptDirection_ puede lanzar tal error. // include_code @@ -647,7 +393,7 @@ function promptDirection(question) { } ---- -(((exception handling)))And the loop can catch it more carefully. +(((exception handling)))Y el bucle _for_ puede atraparlo con más cuidado. // test: no @@ -667,15 +413,11 @@ for (;;) { } ---- -(((debugging)))This will catch only instances of `InputError` and let -unrelated exceptions through. If you reintroduce the typo, the -undefined variable error will be properly reported. +(((debugging)))Esto captura sólo instancias de _InputError_ y permite excepciones a través de _throw_. Si reintroduce el error de tipeo, el error de variable _undefined_ se informará correctamente. == Assertions == -(((assert function)))(((assertion)))(((debugging)))_Assertions_ are a -tool to do basic sanity checking for programmer errors. Consider this -helper function, `assert`: +(((assert function)))(((assertion)))(((debugging)))Las afirmaciones son una herramienta para comprobar la salud básica de los errores de programación. Considere la función auxiliar _assert_: [source,javascript] ---- @@ -696,52 +438,26 @@ function lastElement(array) { ---- (((validation)))(((run-time -error)))(((crash)))(((assumption)))(((array)))This provides a -compact way to enforce expectations, helpfully blowing up the program -if the stated condition does not hold. For instance, the `lastElement` -function, which fetches the last element from an array, would return -`undefined` on empty arrays if the assertion was omitted. Fetching the -last element from an empty array does not make much sense, so it is -almost certainly a programmer error to do so. - -(((assertion)))(((debugging)))Assertions are a way to make sure -mistakes cause failures at the point of the mistake, rather than -silently producing nonsense values that may go on to cause trouble in -an unrelated part of the system. - -== Summary == - -Mistakes and bad input are facts of life. Bugs in programs need to be -found and fixed. They can become easier to notice by having automated -test suites and adding assertions to your programs. - -Problems caused by factors outside the program's control should -usually be handled gracefully. Sometimes, when the problem can be -handled locally, special return values are a sane way to track them. -Otherwise, exceptions are preferable. - -Throwing an exception causes the call stack to be unwound until the -next enclosing `try/catch` block or until the bottom of the stack. -The exception value will be given to the `catch` block that catches -it, which should verify that it is actually the expected kind of -exception and then do something with it. To deal with the -unpredictable control flow caused by exceptions, `finally` blocks can -be used to ensure a piece of code is _always_ run when a block -finishes. - -== Exercises == +error)))(((crash)))(((assumption)))(((array)))Esto proporciona una manera compacta de cumplir las expectativas, ayudando a alertar del programa si la condición declarada no se cumple. Por ejemplo, la función _lastElement_, que recupera el último elemento de una matriz, retornaría indefinidamente arrays vacíos si la aserción (_assertion_) se omitiera. Obtener el último elemento de una matriz vacía no tiene mucho sentido, por lo que es casi seguro que es el resultado de un error de programador. + +(((assertion)))(((debugging)))Las afirmaciones (_Assertions_) son una manera de asegurarse de que los errores causan fallas en el punto del error, en lugar de producir silenciosamente valores sin sentido que pueden causar problemas en una parte no relacionada del sistema. + +== Resumén == + +Los errores y malas aportaciones son hechos de la vida. Los errores en los programas necesitan ser encontrados y arreglados. Pueden ser más fáciles de notar al tener suites de pruebas (_test suites_) automatizadas y añadir aserciones a sus programas. + +Los problemas causados por factores ajenos al control del programa normalmente deben manejarse con gracia. A veces, cuando el problema se puede manejar localmente, los valores de retorno especiales son una forma sana de rastrearlos. De lo contrario, las excepciones son preferibles. + +El lanzamiento de una excepción provoca que la pila de llamadas se desenrolle hasta el siguiente bloque de _try_/_catch_ o hasta la parte inferior de la pila. El valor de excepción se dará al bloque de _catch_ que lo captura, lo que debería comprobar que es realmente el tipo esperado de excepción y luego hacer algo con él. Para manejar el flujo de control impredecible causado por las excepciones, finalmente los bloques se pueden usar para asegurar que un pedazo de código siempre se ejecuta al finalizar un bloque. + +== Ejercicios == === Retry === (((primitiveMultiply (exercise))))(((exception handling)))(((throw -keyword)))Say you have a function `primitiveMultiply` that, in 50 percent of -cases, multiplies two numbers, and in the other 50 percent, raises an -exception of type `MultiplicatorUnitFailure`. Write a function that -wraps this clunky function and just keeps trying until a call -succeeds, after which it returns the result. +keyword)))Digamos que tiene una función primitiveMultiply que, en el 50 por ciento de los casos, multiplica dos números, y en el otro 50 por ciento, plantea una excepción del tipo MultiplicatorUnitFailure. Escribir una función que envuelva esta mala función y sigue intentandolo hasta que una llamada tenga éxito, después de lo cual devuelva el resultado. -(((catch keyword)))Make sure you handle only the exceptions you -are trying to handle. +(((catch keyword)))Asegúrese de manejar solo las excepciones que desea manejar. ifdef::interactive_target[] @@ -767,25 +483,18 @@ console.log(reliableMultiply(8, 8)); ---- endif::interactive_target[] -!!hint!! +!!pista!! (((primitiveMultiply (exercise))))(((try keyword)))(((catch -keyword)))(((throw keyword)))The call to `primitiveMultiply` should -obviously happen in a `try` block. The corresponding `catch` block -should rethrow the exception when it is not an instance of -`MultiplicatorUnitFailure` and ensure the call is retried when it is. +keyword)))(((throw keyword)))La llamada a _primitiveMultiply_ obviamente ocurre en un bloque _try_. El bloque _catch_ correspondiente debe volver a crear la excepción cuando no es una instancia de _MultiplicatorUnitFailure_ y asegurarse de que la llamada se reintente cuando si lo es. -To do the retrying, you can either use a loop that breaks only when a -call succeeds—as in the link:08_error.html#look[`look` example] -earlier in this chapter—or use ((recursion)) and hope you don't get a -string of failures so long that it overflows the stack (which is a -pretty safe bet). +Para hacer el reintento, puede utilizar un bucle que se rompe sólo cuando una llamada tiene éxito -como en el ejemplo de vista anterior en este capítulo- o recursión de uso (_use recursion_) y espero que no obtenga una cadena de errores tan larga que se desborda la pila (Lo qué seguro ocurrirá). -!!hint!! +!!pista!! -=== The locked box === +=== La caja cerrada === -(((locked box (exercise))))Consider the following (rather contrived) +(((locked box (exercise))))Considere el siguiente (y bastante artificial) objeto: object: // include_code @@ -799,20 +508,14 @@ var box = { _content: [], get content() { if (this.locked) throw new Error("Locked!"); - return this._content; + return this.cContent; } }; ---- -(((private property)))(((access control)))It is a ((box)) with a -lock. Inside is an array, but you can get at it only when the box is -unlocked. Directly accessing the `_content` property is not allowed. +(((private property)))(((access control)))It is a ((box)) Es una caja con una cerradura. Dentro hay una matriz, pero sólo se puede obtener cuando se desbloquea la caja. No se permite acceder directamente a la propiedad _cContent_. -(((finally keyword)))(((exception handling)))Write a function called -`withBoxUnlocked` that takes a function value as argument, unlocks the -box, runs the function, and then ensures that the box is locked again -before returning, regardless of whether the argument function returned -normally or threw an exception. +(((finally keyword)))(((exception handling)))Escriba una función llamada _WithBoxUnlocked_ que toma un valor de función como argumento, desbloquea la casilla, ejecuta la función y, a continuación, asegura que la casilla se bloquea de nuevo antes de volver, independientemente de si la función de argumento ha devuelto normalmente o ha lanzado una excepción. ifdef::interactive_target[] @@ -837,21 +540,14 @@ console.log(box.locked); // → true ---- -For extra points, make sure that if you call `withBoxUnlocked` when -the box is already unlocked, the box stays unlocked. +Para obtener puntos adicionales, asegúrese de que si llama a WithBoxUnlocked cuando la caja ya está desbloqueada, la caja permanezca desbloqueada. endif::interactive_target[] -!!hint!! +!!pista!! -(((locked box (exercise))))(((finally keyword)))(((try keyword)))This -exercise calls for a `finally` block, as you probably guessed. Your -function should first unlock the box and then call the argument function -from inside a `try` body. The `finally` block after it should lock the -box again. +(((locked box (exercise))))(((finally keyword)))(((try keyword)))Este ejercicio requiere un bloque _finally_, como usted probablemente adivinó. Su función primero debe desbloquear la caja y luego llamar a la función de argumento desde dentro de un _try_. El bloque _finally_ después debe bloquear la caja de nuevo. -To make sure we don't lock the box when it wasn't already locked, -check its lock at the start of the function and unlock and lock -it only when it started out locked. +Para cerciorarse de que no bloqueamos la caja cuando todavía no estaba bloqueada, revisar su bloqueo al inicio de la función y desbloquearla y bloquearla sólo cuando empezó bloqueada. -!!hint!! +!!pista!! diff --git a/09_regexp.txt b/09_regexp.txt index 13680a0a8..1dae9cfac 100644 --- a/09_regexp.txt +++ b/09_regexp.txt @@ -2,14 +2,12 @@ :prev_link: 08_error :next_link: 10_modules -= Regular Expressions = += Expresiones Regulares = [chapterquote="true"] [quote,Jamie Zawinski] ____ -Some people, when confronted with a -problem, think ‘I know, I'll use regular expressions.’ Now they have -two problems. +Algunas personas, cuando se enfrentan a un problema, dicen 'ya sé, usaré expresiones regulares'. entonces tienen dos problemas. ____ ifdef::interactive_target[] @@ -17,40 +15,21 @@ ifdef::interactive_target[] [chapterquote="true"] [quote, Master Yuan-Ma, The Book of Programming] ____ -Yuan-Ma said, ‘When you cut against the grain of the wood, much -strength is needed. When you program against the grain of a problem, -much code is needed.’ +Yuan-Ma dijo: "Cuando se corta contra la veta de la madera, se necesita mucha fuerza. Cuando se programa contra la lógica de un problema, se necesita mucho código." ____ endif::interactive_target[] (((Zawinski+++,+++ -Jamie)))(((evolution)))(((adoption)))(((integration)))Programming -((tool))s and techniques survive and spread in a chaotic, evolutionary -way. It's not always the pretty or brilliant ones that win but rather -the ones that function well enough within the right niche—for example, -by being integrated with another successful piece of technology. - -(((domain-specific language)))In this chapter, I will discuss one such -tool, _((regular expression))s_. Regular expressions are a way to -describe ((pattern))s in string data. They form a small, separate -language that is part of JavaScript and many other languages and -tools. - -(((interface,design)))Regular expressions are both terribly awkward -and extremely useful. Their syntax is cryptic, and the programming -((interface)) JavaScript provides for them is clumsy. But they are a -powerful ((tool)) for inspecting and processing strings. Properly -understanding regular expressions will make you a more effective -programmer. - -== Creating a regular expression == - -(((regular expression,creation)))(((RegExp constructor)))(((literal -expression)))(((slash character)))A regular expression is a type of -object. It can either be constructed with the `RegExp` constructor or -written as a literal value by enclosing the pattern in forward slash -(`/`) characters. +Jamie)))(((evolution)))(((adoption)))(((integration)))Las herramientas y técnicas de programación sobreviven y se propagan de una manera caótica y evolutiva. No siempre son las formas mas bonitas y luminosos las que ganan, sino las que funcionan lo suficientemente bien en el nicho adecuado. Por ejemplo, aquellas que estan correctamente integrada con otra pieza tecnologica. + +(((domain-specific language)))En este capítulo, hablaré de una de esas herramientas, las expresiones regulares. Las expresiones regulares son una forma de describir patrones en los datos tipo cadena. Forman un lenguaje pequeño y separado que forma parte de JavaScript y muchos otros idiomas y herramientas. + +(((interface,design)))Las expresiones regulares son terriblemente incómodas y extremadamente útiles. Su sintaxis es críptica, y la interfaz de programación que proporciona JavaScript es torpe. Pero son una poderosa herramienta para inspeccionar y procesar cadenas. La correcta comprensión de expresiones regulares le hará un programador más eficaz. + +== Creación de una expresión regular == + +(((regular expression,creation)))(((RegExp constructor)))(((literal expression)))(((slash character)))Una expresión regular es un tipo de objeto. Puede construirse con el constructor `_RegExp_` o escribirse como un valor literal encerrando el patrón en caracteres de barra diagonal (`_/_`). [source,javascript] ---- @@ -58,43 +37,23 @@ var re1 = new RegExp("abc"); var re2 = /abc/; ---- -Both of these regular expression objects represent the same -((pattern)): an _a_ character followed by a _b_ followed by a _c_. +Ambos objetos de expresión regular representan el mismo patrón ((pattern)): un carácter _a_ seguido de un _b_ seguido de un _c_. -(((backslash character)))(((RegExp constructor)))When using the -`RegExp` constructor, the pattern is written as a normal string, so -the usual rules apply for backslashes. +(((backslash character)))(((RegExp constructor)))Cuando se utiliza el constructor `_RegExp_`, el patrón se escribe como una cadena normal, por lo que se aplican las reglas habituales para las barras invertidas. (((regular expression,escaping)))(((escaping,in regexps)))(((slash -character)))The second notation, where the pattern appears between -slash characters, treats backslashes somewhat differently. First, -since a forward slash ends the pattern, we need to put a backslash -before any forward slash that we want to be _part_ of the pattern. In -addition, backslashes that aren't part of special character codes -(like `\n`) will be _preserved_, rather than ignored as they are in -strings, and change the meaning of the pattern. Some characters, such -as question marks and plus signs, have special meanings in regular -expressions and must be preceded by a backslash if they are meant to -represent the character itself. +character)))La segunda notación, donde el patrón aparece entre los caracteres de barra (`_/_`), trata las barras inversas de manera algo diferente. En primer lugar, ya que una barra inclinada termina el patrón, necesitamos poner una barra invertida antes de cualquier barra inclinada que queramos ser parte del patrón. Además, las barras invertidas que no forman parte de códigos de caracteres especiales (como `_\n_`) se conservarán, en lugar de ignorarse como están en cadenas, y cambiaran el significado del patrón. Algunos caracteres, como signos de interrogación (`_?_`) y signos más (`_+_`), tienen significados especiales en expresiones regulares y deben estar precedidos por una barra invertida si están destinados a representar el carácter en sí. [source,javascript] ---- var eighteenPlus = /eighteen\+/; ---- -Knowing precisely what characters to backslash-escape when writing -regular expressions requires you to know every character with a -special meaning. For the time being, this may not be realistic, so -when in doubt, just put a backslash before any character that is not a -letter, number, or ((whitespace)). +Saber cuales carácteres deben usar la barra invertida y cuales no al momento que se escriben expresiones regulares requiere que usted conozca a cada uno de los carácteres especiales. Como en un principio esto puede ser muy engorroso, es recomendable que en caso de duda, sólo ponga una barra invertida antes de cualquier carácter que no sea una letra, número o espacio en blanco. -== Testing for matches == +== Testeando las coincidencias (matches) == -(((matching)))(((test method)))(((regular expression,methods)))Regular -expression objects have a number of methods. The simplest one is -`test`. If you pass it a string, it will return a ((Boolean)) telling -you whether the string contains a match of the pattern in the -expression. +(((matching)))(((test method)))(((regular expression,methods))) Los objetos de expresiones regulares tienen varios métodos. El más simple es `_test_`. Si le pasas una cadena, devolverá un booleano diciéndote si la cadena contiene una coincidencia con el patrón de la expresión propuesta. [source,javascript] ---- @@ -104,23 +63,15 @@ console.log(/abc/.test("abxde")); // → false ---- -(((pattern)))A ((regular expression)) consisting of only nonspecial -characters simply represents that sequence of characters. If _abc_ -occurs anywhere in the string we are testing against (not just at the -start), `test` will return `true`. +(((pattern)))Una expresión regular que consta sólo de caracteres no especiales representa simplemente esa secuencia de caracteres. Si “abc” se produce en cualquier parte de la cadena que estamos probando (no sólo al principio), el metodo `_test_` devolverá `_true_`. -== Matching a set of characters == +== Matchear un conjunto de caracteres == -(((regular expression)))(((indexOf method)))Finding out whether a -string contains _abc_ could just as well be done with a call to -`indexOf`. Regular expressions allow us to go beyond that and express -more complicated ((pattern))s. +(((regular expression)))(((indexOf method))) Descubrir si una cadena contiene _abc_ podría hacerse con una llamada al método `_indexOf_`. Las expresiones regulares nos permiten ir más allá y expresar patrones más complicados. -Say we want to match any ((number)). In a regular expression, putting -a ((set)) of characters between square brackets makes that part of the -expression match any of the characters between the brackets. +Digamos que queremos buscar en una cadena cualquier número del 0 al 9. En una expresión regular, poner un conjunto de caracteres entre corchetes (`_[]_`) hace en la expresión de destino busque coincidencias con cualquiera de los caracteres entre los corchetes. -Both of the following expressions match all strings that contain a ((digit)): +Las dos expresiones siguientes coinciden con todas las cadenas que contienen un dígito: [source,javascript] ---- @@ -130,31 +81,22 @@ console.log(/[0-9]/.test("in 1992")); // → true ---- -(((dash character)))Within square brackets, a dash (`-`) between two -characters can be used to indicate a ((range)) of characters, where -the ordering is determined by the character's ((Unicode)) number. -Characters 0 to 9 sit right next to each other in this ordering -(codes 48 to 57), so `[0-9]` covers all of them and matches any -((digit)). +(((dash character))) Entre corchetes, se puede utilizar un guión (`_-_`) entre dos caracteres para indicar un rango, donde el orden se determina por el número ((Unicode)) de cada cáracter. Como los caracteres `_0_` a `_9_` se sitúan uno al lado del otro en este orden (códigos 48 a 57), entonces `_[0-9]_` cubre todos ellos y coincide con cualquier dígito. -(((whitespace)))(((alphanumeric character)))(((period -character)))There are a number of common character groups that have -their own built-in shortcuts. Digits are one of them: `\d` means the -same thing as `[0-9]`. +(((whitespace)))(((alphanumeric character)))(((period character)))Hay una serie de grupos de caracteres comunes que tienen sus propios atajos incorporados. Los dígitos son uno de ellos: `_\d_` significa lo mismo que `_[0-9]_`. [cols="1,5"] |==== -|`\d` |Any ((digit)) character -|`\w` |An alphanumeric character (“((word character))”) -|`\s` |Any ((whitespace)) character (space, tab, newline, and similar) -|`\D` |A character that is _not_ a digit -|`\W` |A nonalphanumeric character -|`\S` |A nonwhitespace character -|`.` |Any character except for newline(((newline character))) +|`\d` |Cualquier carácter de dígito +|`\w` |Un carácter alfanumérico (carácter de texto o (“((_word character_))”) +|`\s` |Cualquier espacio en blanco (espacio, pestaña, nueva línea y similar) +|`\D` |Carácter que _no_ es un dígito +|`\W` |Un carácter no alfanumérico +|`\S` |Un carácter no-espacio-en-blanco +|`.` |Cualquier carácter excepto carácter de nueva línea (((newline))) |==== -So you could match a ((date)) and ((time)) format like 30-01-2003 -15:20 with the following expression: +Así que se podría coincidir (_matchear_) con un formato de fecha y hora como 30-01-2003 15:20 con la siguiente expresión: [source,javascript] ---- @@ -165,23 +107,11 @@ console.log(dateTime.test("30-jan-2003 15:20")); // → false ---- -(((backslash character)))That looks completely awful, doesn't it? It has way too -many backslashes, producing background noise that makes it hard to -spot the actual ((pattern)) expressed. We'll see a slightly improved -version of this expression -link:09_regexp.html#date_regexp_counted[later]. +(((backslash character)))Se ve horrible, ¿verdad? Tiene demasiadas barras invertidas y es difícil detectar el patrón real expresado. Veremos una versión ligeramente mejorada de esta expresión más adelante link:09_regexp.html#date_regexp_counted[más adelante]. -(((escaping,in regexps)))(((regular expression)))(((set)))These -backslash codes can also be used inside ((square brackets)). For -example, `[\d.]` means any digit or a period character. But note that -the period itself, when used between square brackets, loses its -special meaning. The same goes for other special characters, such as -`+`. +(((escaping,in regexps)))(((regular expression)))(((set)))Estos códigos de barra invertida también se pueden utilizar dentro de corchetes. Por ejemplo, `_[\ d.]_` significa cualquier dígito o un carácter de período. Pero tenga en cuenta que el propio período, cuando se usa entre corchetes, pierde su significado especial. Lo mismo ocurre con otros caracteres especiales, como `_+_`. -(((square brackets)))(((inversion)))(((caret character)))To _invert_ a -set of characters—that is, to express that you want to match any -character _except_ the ones in the set—you can write a caret (`^`) -character after the opening bracket. +(((square brackets)))(((inversion)))(((caret character)))Para _invertir_ un conjunto de caracteres, es decir, para expresar que desea que coincida con cualquier carácter _excepto_ los del conjunto, puede escribir (`^`) después del corchete de apertura. [source,javascript] ---- @@ -192,16 +122,11 @@ console.log(notBinary.test("1100100010200110")); // → true ---- -== Repeating parts of a pattern == +== Repitiendo partes de un patrón == -(((regular expression,repetition)))We now know how to match a single digit. What -if we want to match a whole number—a ((sequence)) of one or more -((digit))s? +(((regular expression,repetition)))Ya sabemos cómo hacer coincidir un solo dígito. ¿Qué pasa si queremos igualar un número entero? ¿Una secuencia de uno o más dígitos? -(((plus character)))(((repetition)))(((+ operator)))When you put a -plus sign (`+`) after something in a regular expression, it indicates -that the element may be repeated more than once. Thus, `/\d+/` matches -one or more digit characters. +(((plus character)))(((repetition)))(((+ operator))) Cuando se coloca un signo más (`_+_`) después de algo en una expresión regular, indica que el elemento se puede repetir más de una vez. Así, `_/\d+/_` coincide con uno o más caracteres de dígito. [source,javascript] ---- @@ -215,15 +140,9 @@ console.log(/'\d*'/.test("''")); // → true ---- -(((pass:[*] operator)))(((asterisk)))The star (`*`) has a similar -meaning but also allows the pattern to match zero times. Something -with a star after it never prevents a pattern from matching—it'll just -match zero instances if it can't find any suitable text to match. +(((pass:[*] operator)))(((asterisk)))El asterisco (_`*`_) tiene un significado similar, pero también permite que el patrón coincida cero veces. Algo con un _`*`_ al final, nunca impide un patrón de emparejamiento. Igualará cero instancias si no puede encontrar cualquier texto adecuado al patrón. -(((British English)))(((American English)))(((question mark)))A -question mark makes a part of a pattern “((optional))”, meaning it may -occur zero or one time. In the following example, the _u_ character -is allowed to occur, but the pattern also matches when it is missing. +(((British English)))(((American English)))(((question mark)))Un signo de interrogación (_`?`_) hace que una parte de un patrón sea "opcional", lo que significa que puede ocurrir ninguna o una vez. En el ejemplo siguiente, se permite que el carácter _u_ se produzca, pero el patrón también coincide (_matchea_) cuando este falta. [source,javascript] ---- @@ -234,16 +153,10 @@ console.log(neighbor.test("neighbor")); // → true ---- -(((repetition)))(((curly braces)))To indicate that a pattern should -occur a precise number of times, use curly braces. Putting `{4}` after -an element, for example, requires it to occur exactly four times. It -is also possible to specify a ((range)) this way: `{2,4}` means the -element must occur at least twice and at most four times. +(((repetition)))(((curly braces)))Para indicar que un patrón debe ocurrir un número exacto de veces, utilice llaves (_`{}`_). Poner `_{4}_` después de un elemento, por ejemplo, indica que se requiere que el elemento se encuentre (o matchee) exactamente cuatro veces. También es posible especificar un rango de esta manera: `_{2,4}_` significa que el elemento debe ocurrir al menos dos veces y como máximo cuatro veces. [[date_regexp_counted]] -Here is another version of the ((date)) and ((time)) pattern that -allows both single- and double-((digit)) days, months, and hours. It -is also slightly more readable. +Aquí hay otra versión del patrón de fecha y hora que permite los días, meses y horas de un solo dígito y dos dígitos, lo que lo hace más agradable y fácil de leer. [source,javascript] ---- @@ -252,17 +165,11 @@ console.log(dateTime.test("30-1-2003 8:45")); // → true ---- -You can also specify open-ended ((range))s when using ((curly -braces)) by omitting the number on either side of the comma. So -`{,5}` means zero to five times, and `{5,}` means five or more times. +También puede especificar rangos abiertos cuando se usan llaves, omitiendo el número después de la coma. Así que `_{5,}_` significa cinco o más veces. -== Grouping subexpressions == +== Agrupar subexpresiones == -(((regular expression,grouping)))(((grouping)))To use an operator like `*` or -`+` on more than one element at a time, you can use ((parentheses)). A -part of a regular expression that is enclosed in parentheses counts -as a single element as far as the operators following it are -concerned. +(((regular expression,grouping)))(((grouping)))Para usar un operador como `_*_` o `_+_` en más de un elemento a la vez, puede utilizar paréntesis `_()_`. Una parte de una expresión regular que está encerrada entre paréntesis cuenta como un solo elemento en lo que se refiere a los operadores que lo siguen. [source,javascript] ---- @@ -271,24 +178,14 @@ console.log(cartoonCrying.test("Boohoooohoohooo")); // → true ---- -(((crying)))The first and second `+` characters apply only to the -second _o_ in _boo_ and _hoo_, respectively. The third `+` applies to -the whole group `(hoo+)`, matching one or more sequences like that. +(((crying)))El primer `_+_` y el segundo `_+_` se aplican solamente al segundo `_o_` en `_boo_` y `_hoo_`, respectivamente. El tercero `_+_` se aplica a todo el grupo `_(hoo+)_`, haciendo coincidir una o más secuencias como esa. (((case sensitivity)))(((capitalization)))(((regular -expression,flags)))The `i` at the end of the expression in the -previous example makes this regular expression case insensitive, allowing it to -match the uppercase _B_ in the input string, even though the pattern -is itself all lowercase. +expression,flags)))El `_i_` al final de la expresión en el ejemplo anterior hace que esta expresión regular no sea sensible a mayúsculas y minúsculas (case insensitive), permitiendo que coincida con la mayúscula _B_ en la cadena de entrada, aunque el patrón es todo en minúsculas. -== Matches and groups == +== Matcheos y grupos == -(((regular expression,grouping)))(((exec method)))(((array)))The `test` method -is the absolute simplest way to match a regular expression. It -tells you only whether it matched and nothing else. Regular expressions -also have an `exec` (execute) method that will return `null` if no -match was found and return an object with information about the match -otherwise. +(((regular expression,grouping)))(((exec method)))(((array)))El método `_test_` es la forma más simple de buscar coincidencias con una expresión regular. Sólo dice si coincide y nada más. Las expresiones regulares también tienen un método `_exec_` (ejecutar) que devolverá `_null_` si no se encontró ninguna coincidencia o, si encontró una, devolverá un objeto con información sobre la coincidencia. [source,javascript] ---- @@ -299,15 +196,9 @@ console.log(match.index); // → 8 ---- -(((index property)))(((string,indexing)))An object returned from -`exec` has an `index` property that tells us _where_ in the string the -successful match begins. Other than that, the object looks like (and -in fact is) an array of strings, whose first element is the string -that was matched—in the previous example, this is the sequence of -((digit))s that we were looking for. +(((index property)))(((string,indexing)))Un objeto devuelto desde el método `_exec_` tiene una propiedad `_índex_` que nos dice en dónde comienza la coincidencia correcta en la cadena. Aparte de eso, el objeto se ve como (y de hecho es) una matriz de cadenas, cuyo primer elemento es la cadena que matcheó (en el ejemplo anterior, ésta es la secuencia de dígitos que estábamos buscando). -(((string,methods)))(((match method)))String values have a `match` -method that behaves similarly. +(((string,methods)))(((match method)))Los valores de cadena tienen un método `_match_` de coincidencia que se comporta de manera similar. [source,javascript] ---- @@ -315,12 +206,7 @@ console.log("one two 100".match(/\d+/)); // → ["100"] ---- -(((grouping)))(((capture group)))(((exec method)))When the regular -expression contains subexpressions grouped with parentheses, the text -that matched those groups will also show up in the array. The whole -match is always the first element. The next element is the part -matched by the first group (the one whose opening parenthesis comes -first in the expression), then the second group, and so on. +(((grouping)))(((capture group)))(((exec method)))Cuando la expresión regular contiene subexpresiones agrupadas con paréntesis, el texto que coincida con esos grupos también aparecerá en la matriz. Todo el `_match_` es siempre el primer elemento. El siguiente elemento es la parte que coincidió por el primer grupo (aquel cuyo paréntesis de apertura viene primero en la expresión), luego el segundo grupo, y así sucesivamente. [source,javascript] ---- @@ -329,10 +215,7 @@ console.log(quotedText.exec("she said 'hello'")); // → ["'hello'", "hello"] ---- -(((capture group)))When a group does not end up being matched at all -(for example, when followed by a question mark), its position in the -output array will hold `undefined`. Similarly, when a group is matched -multiple times, only the last match ends up in the array. +(((capture group)))Cuando un grupo no encuentra coincidencia en absoluto (por ejemplo, cuando es seguido por un signo de interrogación), su posición en la matriz de salida se mantendrá indefinida. Del mismo modo, cuando un grupo es matcheado varias veces, sólo el último match termina en la matriz. [source,javascript] ---- @@ -343,21 +226,13 @@ console.log(/(\d)+/.exec("123")); ---- (((exec method)))(((regular -expression,methods)))(((extraction)))Groups can be useful for -extracting parts of a string. If we don't just want to verify whether -a string contains a ((date)) but also extract it and construct an -object that represents it, we can wrap parentheses around the digit -patterns and directly pick the date out of the result of `exec`. +expression,methods)))(((extraction)))Los grupos pueden ser útiles para extraer partes de una cadena. Si no queremos solamente verificar si una cadena contiene una fecha sino también queremos extraerla y construir un objeto que la represente, podemos insertar paréntesis alrededor de los patrones de dígitos y escoger directamente la fecha del resultado de `_exec_`. -But first, a brief detour, in which we discuss the preferred way to -store date and ((time)) values in JavaScript. +Pero primero, un breve desvío en el que discutimos la forma preferida de almacenar valores de fecha y hora en JavaScript. -== The date type == +== El tipo fecha == -(((constructor)))(((Date constructor)))JavaScript has a standard -object type for representing ((date))s—or rather, points in ((time)). -It is called `Date`. If you simply create a date object using `new`, -you get the current date and time. +(((constructor)))(((Date constructor)))JavaScript tiene un tipo (`_typeof_`) de objeto estándar para representar fechas, o más bien, puntos en el tiempo. Se llama `_Date_`. Si simplemente se crea un objeto `_Date_` con `_new_`, se obtienen la fecha y la hora actual. // test: no @@ -367,8 +242,7 @@ console.log(new Date()); // → Wed Dec 04 2013 14:24:57 GMT+0100 (CET) ---- -(((Date constructor)))You can also create an object for a specific -time. +(((Date constructor)))También puede crear un objeto para una hora específica. [source,javascript] ---- @@ -378,18 +252,11 @@ console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // → Wed Dec 09 2009 12:59:59 GMT+0100 (CET) ---- -(((zero-based counting)))(((interface,design)))JavaScript uses a -convention where month numbers start at zero (so December is 11), yet -day numbers start at one. This is confusing and silly. Be careful. +(((zero-based counting)))(((interface,design)))JavaScript utiliza una convención donde los números de mes empiezan en cero (por lo que diciembre es 11), sin embargo, los números de día empiezan en uno. Esto puede ser muy confuso y tonto. Ten mucho cuidado. -The last four arguments (hours, minutes, seconds, and milliseconds) -are optional and taken to be zero when not given. +Los últimos cuatro argumentos (horas, minutos, segundos y milisegundos) son opcionales y se toman como cero cuando no se dan. -(((getTime method)))Timestamps are stored as the number of -milliseconds since the start of 1970, using negative numbers for -times before 1970 (following a convention set by “((Unix time))”, -which was invented around that time). The `getTime` method on a date object -returns this number. It is big, as you can imagine. +(((getTime method)))Las marcas de tiempo se almacenan como el número de milisegundos desde el comienzo de 1970, usando números negativos para tiempos anteriores a 1970 (siguiendo una convención establecida por “((Unix time))” creada en esa decada). El método `_getTime_` en un objeto de `_Date_` devuelve este número. Es un número grande. [source,javascript] ---- @@ -399,23 +266,13 @@ console.log(new Date(1387407600000)); // → Thu Dec 19 2013 00:00:00 GMT+0100 (CET) ---- -(((Date.now function)))(((Date constructor)))If you give the `Date` -constructor a single argument, that argument is treated as such -a millisecond count. You can get the current millisecond count by -creating a new `Date` object and calling `getTime` on it but also by -calling the `Date.now` function. +(((Date.now function)))(((Date constructor)))Si le da al constructor `_Date_` un solo argumento, ese argumento se trata como un recuento de milisegundos. Puede obtener el recuento actual de milisegundos creando un nuevo objeto `_Date_` y llamando a `_getTime_`, pero también llamando a la función `_Date.now_`. (((getFullYear method)))(((getMonth method)))(((getDate method)))(((getHours method)))(((getMinutes method)))(((getSeconds -method)))(((getYear method)))Date objects provide methods like -`getFullYear`, `getMonth`, `getDate`, `getHours`, `getMinutes`, and -`getSeconds` to extract their components. There's also `getYear`, -which gives you a rather useless two-digit year value (such as `93` or -`14`). +method)))(((getYear method)))Los objetos `_Date_` proporcionan métodos como `_getFullYear_`, `_getMonth_`, `_getDate_`, `_getHours_`, `_getMinutes_` y `_getSeconds_` para extraer sus componentes. También hay un método `_getYear_` que da un valor de año de dos dígitos bastante inútil (como 93 o 14). -(((capture group)))Putting ((parentheses)) around the parts of the -expression that we are interested in, we can now easily create a date -object from a string. +(((capture group)))Poniendo paréntesis alrededor de las partes de la expresión que nos interesa, ahora podemos crear fácilmente un objeto `_Date_` a partir de una cadena. [source,javascript] ---- @@ -432,25 +289,11 @@ console.log(findDate("30-1-2003")); == Word and string boundaries == -(((matching)))(((regular expression,boundary)))Unfortunately, -`findDate` will also happily extract the nonsensical date 00-1-3000 -from the string `"100-1-30000"`. A match may happen anywhere in the -string, so in this case, it'll just start at the second character and -end at the second-to-last character. - -(((boundary)))(((caret character)))(((dollar sign)))If we want to -enforce that the match must span the whole string, we can add the -markers `^` and `$`. The caret matches the start of the input string, -while the dollar sign matches the end. So, `/^\d+$/` matches a string -consisting entirely of one or more digits, `/^!/` matches any string -that starts with an exclamation mark, and `/x^/` does not match any -string (there cannot be an _x_ before the start of the string). - -(((word boundary)))(((word character)))If, on the other hand, we just -want to make sure the date starts and ends on a word boundary, we can -use the marker `\b`. A word boundary can be the start or end of the -string or any point in the string that has a word character (as in -`\w`) on one side and a nonword character on the other. +(((matching)))(((regular expression,boundary)))Desafortunadamente, `_findDate_` también obtendra fechas sin sentido del tipo 00-1-3000 de la cadena _"100-1-30000"_. Una coincidencia puede ocurrir en cualquier parte de la cadena, por lo que en este caso, sólo comenzará en el segundo carácter y finalizará en el segundo al último carácter. + +(((boundary)))(((caret character)))(((dollar sign)))Si queremos hacer que la coincidencia abarque toda la cadena, podemos agregar los marcadores _`^`_ y _`$`_. El _`^`_ coincide con el inicio de la cadena de entrada, mientras que _`$`_ coincide con el final. Por lo tanto, _`/^\d+$/`_ coincide con una cadena compuesta enteramente de uno o más dígitos, _`/^!/`_ coincide con cualquier cadena que comience con un signo de exclamación y _`/x^/`_ no coincide con ninguna cadena (no puede haber una _`x`_ antes el comienzo de la cadena). + +(((word boundary)))(((word character)))Si, por el contrario, sólo queremos asegurarnos de que la fecha empiece y termine en un límite de palabra, podemos usar el marcador _`\b`_. Un límite de palabra puede ser el comienzo o el final de la cadena o cualquier punto de la cadena que tenga un carácter de palabra (como en _`\w`_) en un lado y un carácter _`nonword`_ en el otro. [source,javascript] ---- @@ -460,22 +303,14 @@ console.log(/\bcat\b/.test("concatenate")); // → false ---- -(((matching)))Note that a boundary marker doesn't represent an actual -character. It just enforces that the regular expression matches only -when a certain condition holds at the place where it appears in the -pattern. +(((matching)))Tenga en cuenta que un marcador de límite no representa un carácter real. Sólo hace que la expresión regular coincida solamente si una determinada condición se mantiene donde aparece en el patrón. -== Choice patterns == +== Patrones de elección == (((branching)))(((regular expression,alternatives)))(((farm -example)))Say we want to know whether a piece of text contains not -only a number but a number followed by one of the words _pig_, _cow_, -or _chicken_, or any of their plural forms. +example)))Digamos que no queremos saber si una parte del texto contiene un número, sino que buscamos un número seguido por una de las palabras _pig_, _cow_ o _chicken_, o cualquiera de sus formas plurales. -We could write three regular expressions and test them in turn, but -there is a nicer way. The ((pipe character)) (`|`) denotes a -((choice)) between the pattern to its left and the pattern to its -right. So I can say this: +Podríamos escribir tres expresiones regulares y probarlas a su vez, pero hay una manera más agradable. El carácter _|_ (tubo) indica una opción entre el patrón a su izquierda y el patrón a su derecha. Así que puedo decir esto: [source,javascript] ---- @@ -486,130 +321,59 @@ console.log(animalCount.test("15 pigchickens")); // → false ---- -(((parentheses)))Parentheses can be used to limit the part of the -pattern that the pipe operator applies to, and you can put multiple -such operators next to each other to express a choice between more -than two patterns. +(((parentheses)))Los paréntesis _()_ se pueden usar para limitar la parte del patrón a la que se aplica el operador _|_ (tubo) y se pueden poner varios operadores de este tipo, uno al lado del otro, para expresar opciones entre más de dos patrones. -== The mechanics of matching == +== La mecánica del matcheo o coincidencia == -(((regular expression,matching)))(((matching,algorithm)))Regular -expressions can be thought of as ((flow diagram))s. This is the -diagram for the livestock expression in the previous example: +(((regular expression,matching)))(((matching,algorithm)))Las expresiones regulares pueden considerarse diagramas de flujo. Este es el diagrama para el ejemplo anterior: image::img/re_pigchickens.svg[alt="Visualization of /\\b\\d+ (pig|cow|chicken)s?\\b/"] -(((traversal)))Our expression matches a string if we can find a path -from the left side of the diagram to the right side. We keep -a current position in the string, and every time we move through a -box, we verify that the part of the string after our current position -matches that box. +(((traversal)))Nuestra expresión coincide (_matchea_) con una cadena de caracteres si podemos seguir el camino desde el lado izquierdo del diagrama hacia el lado derecho. Mantenemos una posición en la cadena y, cada vez que nos movemos a través de una caja, verificamos que la parte de la cadena que dejamos atras coincide con dicha casilla. -So if we try to match `"the 3 pigs"` with our regular expression, -our progress through the flow chart would look like this: +Así que si tratamos de matchear `"the 3 pigs"` con nuestra expresión regular, nuestro progreso a través del diagrama de flujo sería así: - - At position 4, there is a word ((boundary)), so we can move past - the first box. + - En la posición 4, hay un límite de palabras ((_boundary_)), por lo que podemos pasar de la primera casilla. - - Still at position 4, we find a digit, so we can also move past the - second box. + - Todavía en la posición 4, encontramos un dígito, así que también podemos pasar de la segunda caja. - - At position 5, one path loops back to before the second (digit) box, - while the other moves forward through the box that holds a single space - character. There is a space here, not a digit, so we must take the - second path. + - En la posición 5, un camino recorre hacia antes de la segunda (dígito) caja, mientras que el otro se mueve hacia adelante a través de la caja que contiene un solo carácter de espacio. Hay un espacio aquí, no un dígito, así que debemos tomar el segundo camino. - - We are now at position 6 (the start of “pigs”) and at the three-way - branch in the diagram. We don't see “cow” or “chicken” here, but we - do see “pig”, so we take that branch. + - Ahora estamos en la posición 6 (el comienzo de "_pigs_") y en la rama de tres vías en el diagrama. No vemos "_cow_" o "_chiken_" aquí, pero sí vemos "_pig_", así que tomamos esa rama. - - At position 9, after the three-way branch, one path skips - the _s_ box and goes straight to the final word boundary, while the other path - matches an _s_. There is an _s_ character here, not a word boundary, - so we go through the _s_ box. + - En la posición 9, después de la rama de tres vías, una ruta omite la caja _s_ y va directamente al límite final de la palabra, mientras que la otra ruta coincide con una _s_. Hay un carácter de s aquí, no una frontera de la palabra, así que vamos a través de la caja de _s_. - - We're at position 10 (the end of the string) and can match only a - word ((boundary)). The end of a string counts as a word boundary, - so we go through the last box and have successfully matched this - string. + - Estamos en la posición 10 (el final de la cadena) y puede coincidir sólo con un límite de palabra ((_boundary_)). El final de una cadena cuenta como un límite de palabra, por lo que pasamos por el último cuadro y hemos _matcheado_ con esta cadena.. (((regular -expression,matching)))(((matching,algorithm)))(((searching)))Conceptually, -a regular expression engine looks for a match in a string as follows: -it starts at the start of the string and tries a match there. In this -case, there _is_ a word boundary there, so it'd get past the first -box—but there is no digit, so it'd fail at the second box. Then it -moves on to the second character in the string and tries to begin a -new match there... and so on, until it finds a match or reaches the end -of the string and decides that there really is no match. +expression,matching)))(((matching,algorithm)))(((searching)))Conceptualmente, un motor de expresiones regulares busca una coincidencia en una cadena de la siguiente manera: comienza al principio de la cadena e intenta una coincidencia allí. En este caso, hay un límite de palabra (_word boundary_) allí, por lo que pasaría la primera casilla, pero no hay dígitos, por lo que fallaría en la segunda casilla. Luego se mueve al segundo carácter de la cadena e intenta comenzar un nuevo partido allí... y así sucesivamente, hasta que encuentre una coincidencia o llegue al final de la cadena y decida que realmente no hay coincidencia. [[backtracking]] -== Backtracking == +== Retroceso == (((regular expression,backtracking)))(((binary number)))(((decimal number)))(((hexadecimal number)))(((flow -diagram)))(((matching,algorithm)))(((backtracking)))The regular -expression `/\b([01]+b|\d+|[\da-f]+h)\b/` matches either a binary -number followed by a _b_, a regular decimal number with no suffix -character, or a hexadecimal number (that is, base 16, with the letters -_a_ to _f_ standing for the digits 10 to 15) followed by an _h_. This -is the corresponding diagram: +diagram)))(((matching,algorithm)))(((backtracking)))La expresión regular `_/\b([01]+b|\d+|[\da-f]+h)\b/_` coincide con un número binario seguido de _a b_, un número decimal regular sin carácter de sufijo o un número hexadecimal (Es decir, base 16, con las letras de _a - f_ para representar dígitos _10_ a _15_) seguido de _h_. Este es el diagrama correspondiente: image::img/re_number.svg[alt="Visualization of /\\b([01]+b|\\d+|[\\da-f]+h)\\b/"] -(((branching)))When matching this expression, it will often happen -that the top (binary) branch is entered even though the input does not -actually contain a binary number. When matching the string `"103"`, -for example, it becomes clear only at the 3 that we are in the wrong -branch. The string _does_ match the expression, just not the branch we -are currently in. - -(((backtracking)))(((searching)))So the matcher _backtracks_. When -entering a branch, it remembers its current position (in this -case, at the start of the string, just past the first boundary box in -the diagram) so that it can go back and try another branch if the -current one does not work out. For the string `"103"`, after -encountering the 3 character, it will start trying the branch for -decimal numbers. This one matches, so a match is reported after all. - -(((matching,algorithm)))The matcher stops as soon as it finds a full -match. This means that if multiple branches could potentially match a -string, only the first one (ordered by where the branches appear in -the regular expression) is used. - -Backtracking also happens for ((repetition)) operators like + and `*`. -If you match `/^.*x/` against `"abcxe"`, the `.*` part will first try -to consume the whole string. The engine will then realize that it -needs an _x_ to match the pattern. Since there is no _x_ past the end -of the string, the star operator tries to match one character less. -But the matcher doesn't find an _x_ after `abcx` either, so it -backtracks again, matching the star operator to just `abc`. _Now_ it -finds an _x_ where it needs it and reports a successful match from -positions 0 to 4. - -(((performance)))(((complexity)))It is possible to write regular -expressions that will do a _lot_ of backtracking. This problem occurs -when a pattern can match a piece of input in many different ways. For -example, if we get confused while writing a binary-number regular expression, we -might accidentally write something like `/([01]+)+b/`. +(((branching)))Al hacer coincidir esta expresión, sucederá a menudo que la rama superior (binaria) se ingrese aunque la entrada no contenga realmente un número binario. Al buscar en la cadena "_103_", por ejemplo, sólo queda claro en el _3_ que estamos en la rama equivocada. La cadena coincide con la expresión, pero no con la rama en la que estamos actualmente. + +(((backtracking)))(((searching)))Así que el _matcher_ retrocede. Al entrar en una rama recuerda su posición actual (en este caso, al comienzo de la cadena, justo después de la primera caja de límites en el diagrama) para que pueda volver atrás y probar otra rama si la actual no funciona. Para la cadena "_103_", después de encontrar el carácter _3_, comenzará a probar la rama para los números decimales. Éste coincide, por lo que un _match_ es reportado al final de todo. + +(((matching,algorithm)))El _matcher_ se detiene tan pronto como encuentra una coincidencia completa. Esto significa que si varias ramas podrían potencialmente coincidir con una cadena, sólo se utiliza la primera (ordenada según aparecen en la expresión regular). + +El retroceso también ocurre para los operadores de repetición como `_+_` y `_*_`. Si coincide con `_/^.*x/_` contra "_`abcxe_`", la parte `_*_` Intentará primero consumir toda la cadena. El motor entonces se dará cuenta de que necesita una `_x_` para que coincida con el patrón. Puesto que no hay `_x_` superado el final de la cadena, el operador `_*_` intentara igualar un carácter menos. Pero el `_matcher_` tampoco encuentra una `_x_` después de `_abcx_`, por lo que retrocede de nuevo, haciendo coincidir el operador `_*_` con `_abc_`. Ahora si encuentra una `_x_` donde lo necesita e informa de una coincidencia exitosa desde las posiciones `_0_` a `_4_`. + +(((performance)))(((complexity)))Es posible escribir expresiones regulares con mucho retroceso (_backtracking_). Esto se produce cuando un patrón puede coincidir con una pieza de entrada de muchas maneras diferentes. Por ejemplo, si nos confundimos al escribir una expresión regular de un número binario, podríamos escribir algo como `_/([01]+)+b/_`. image::img/re_slow.svg[alt="Visualization of /([01]+)+b/",width="6cm"] -(((inner loop)))(((nesting,in regexps)))If that tries to match some -long series of zeros and ones with no trailing _b_ character, the -matcher will first go through the inner loop until it runs out of -digits. Then it notices there is no _b_, so it backtracks one -position, goes through the outer loop once, and gives up again, trying -to backtrack out of the inner loop once more. It will continue to try -every possible route through these two loops. This means the amount of -work _doubles_ with each additional character. For even just a few -dozen characters, the resulting match will take practically forever. +(((inner loop)))(((nesting,in regexps)))Si intenta hacer coincidir una serie larga de ceros y unos sin ningún carácter _b_, el _matcher_ primero pasará por el bucle interno hasta que se quede sin dígitos. Entonces advierte que no hay _b_, por lo que retrocede una posición, pasa por el bucle externo una vez, y se da de nuevo, tratando de retroceder fuera del bucle interior una vez más. Seguirá intentando cada ruta posible a través de estos dos bucles. Esto significa que la cantidad de trabajo se duplica con cada carácter adicional. Para incluso sólo unas pocas docenas de caracteres, el _matcheo_ resultante puede ser prácticamente eterno. -== The replace method == +== El método de reemplazo == -(((replace method)))(((regular expression)))String values have a -`replace` method, which can be used to replace part of the string -with another string. +(((replace method)))(((regular expression)))Los valores de cadena tienen un método `_replace_`, que se puede usar para reemplazar parte de la cadena con otra cadena. [source,javascript] ---- @@ -617,11 +381,7 @@ console.log("papa".replace("p", "m")); // → mapa ---- -(((regular expression,flags)))(((regular expression,global)))The first -argument can also be a regular expression, in which case the first -match of the regular expression is replaced. When a `g` option (for -_global_) is added to the regular expression, _all_ matches in the -string will be replaced, not just the first. +(((regular expression,flags)))(((regular expression,global)))El primer argumento también puede ser una expresión regular, en cuyo caso la primera coincidencia de la expresión regular se sustituye. Cuando se agrega una opción `_g_` (global) a la expresión regular, _todas_ las coincidencias de la cadena se reemplazarán, no sólo la primera. [source,javascript] ---- @@ -631,20 +391,10 @@ console.log("Borobudur".replace(/[ou]/g, "a")); // → Barabadar ---- -(((interface,design)))(((argument)))It would have been sensible if the -choice between replacing one match or all matches was made through an -additional argument to `replace` or by providing a different method, -`replaceAll`. But for some unfortunate reason, the choice relies on a -property of the regular expression instead. +(((interface,design)))(((argument)))Hubiera sido razonable si la opción entre reemplazar un solo patrón o todos los patrones se hiciera a través de un argumento adicional o proporcionando un método diferente como `_replaceAll_`, pero por alguna razón, esta opción se indica en una propiedad de la misma expresión regular. (((grouping)))(((capture group)))(((dollar sign)))(((replace -method)))(((regular expression,grouping)))The real power of using -regular expressions with `replace` comes from the fact that we can -refer back to matched groups in the replacement string. For example, -say we have a big string containing the names of people, one name per -line, in the format `Lastname, Firstname`. If we want to swap these -names and remove the comma to get a simple `Firstname Lastname` -format, we can use the following code: +method)))(((regular expression,grouping)))El poder real de usar expresiones regulares con `_replace_` viene del hecho de que podemos referirnos de nuevo a los grupos coincidentes en la cadena de reemplazo. Por ejemplo, digamos que tenemos una cadena grande que contiene los nombres de las personas, un nombre por línea, en el formato Apellido, Nombre. Si queremos intercambiar estos nombres y eliminar la coma para obtener un simple formato apellido-nombre, podemos utilizar el siguiente código: [source,javascript] ---- @@ -656,18 +406,11 @@ console.log( // Dennis Ritchie ---- -The `$1` and `$2` in the replacement string refer to the parenthesized -groups in the pattern. `$1` is replaced by the text that matched -against the first group, `$2` by the second, and so on, up to `$9`. -The whole match can be referred to with `$&`. +Los `_$1_` y `_$2_` en la cadena de reemplazo se refieren a los grupos entre paréntesis en el patrón. $1 se sustituye por el texto que coincide con el primer grupo, `_$2_` por el segundo, y así sucesivamente hasta `_$9_`. Todo el `_match_` puede ser referido con `_$&_`. -(((function,higher-order)))(((grouping)))(((capture group)))It is also -possible to pass a function, rather than a string, as the second -argument to `replace`. For each replacement, the function will be -called with the matched groups (as well as the whole match) as -arguments, and its return value will be inserted into the new string. +(((function,higher-order)))(((grouping)))(((capture group)))También es posible pasar una función, en lugar de una cadena, como el segundo argumento a reemplazar. Para cada reemplazo, la función se llamará con los grupos coincidentes (así como la coincidencia completa) como argumentos, y su valor de retorno se insertará en la nueva cadena. -Here's a simple example: +Aquí hay un ejemplo sencillo: [source,javascript] ---- @@ -678,7 +421,7 @@ console.log(s.replace(/\b(fbi|cia)\b/g, function(str) { // → the CIA and FBI ---- -And here's a more interesting one: +Y aquí hay una más interesante: [source,javascript] ---- @@ -695,20 +438,13 @@ console.log(stock.replace(/(\d+) (\w+)/g, minusOne)); // → no lemon, 1 cabbage, and 100 eggs ---- -This takes a string, finds all occurrences of a number followed by an -alphanumeric word, and returns a string wherein every such occurrence -is decremented by one. +Este ejemplo toma una cadena, encuentra todas las veces que aparece un número seguido de una palabra alfanumérica, y devuelve una cadena (_string_) en la que cada una de tales apariciones se decrementa en una. -The `(\d+)` group ends up as the `amount` argument to the function, -and the `(\w+)` group gets bound to `unit`. The function converts -`amount` to a number—which always works, since it matched `\d+`—and -makes some adjustments in case there is only one or zero left. +El grupo `_(\d+)_` termina como el argumento `_amount_` de la función, y el grupo `_(\w+)_` se vincula al argumento `_unit_`. La función convierte `_amount_` en un número -que siempre funciona, ya que coincide con `_\d+-_` y hace algunos ajustes en caso de que sólo quede uno o cero, como quitar el plural o avisar la falta de stock con la palabra “no”. -== Greed == +== Codicia == -(((greed)))(((regular expression)))It isn't hard to use `replace` to -write a function that removes all ((comment))s from a piece of -JavaScript ((code)). Here is a first attempt: +(((greed)))(((regular expression)))No es difícil utilizar `_replace_` para escribir una función que elimina todos los comentarios de una pieza de código JavaScript. He aquí un primer intento: // test: wrap @@ -726,37 +462,15 @@ console.log(stripComments("1 /* a */+/* b */ 1")); ---- (((period character)))(((slash character)))(((newline -character)))(((empty set)))(((block comment)))(((line comment)))The -part before the _or_ operator simply matches two slash characters -followed by any number of non-newline characters. The part for -multiline comments is more involved. We use `[^]` (any character that -is not in the empty set of characters) as a way to match any -character. We cannot just use a dot here because block comments can -continue on a new line, and dots do not match the newline character. - -But the output of the previous example appears to have gone wrong. Why? - -(((backtracking)))(((greed)))(((regular expression)))The `[^]*` part of -the expression, as I described in the section on backtracking, will -first match as much as it can. If that causes the next part of the -pattern to fail, the matcher moves back one character and tries again -from there. In the example, the matcher first tries to match the whole -rest of the string and then moves back from there. It will find an -occurrence of `*/` after going back four characters and match that. -This is not what we wanted—the intention was to match a single -comment, not to go all the way to the end of the code and find the end -of the last block comment. - -Because of this behavior, we say the repetition operators (`+`, `*`, -`?`, and `{}`) are _((greed))y_, meaning they match as much as they -can and backtrack from there. If you put a ((question mark)) after -them (`+?`, `*?`, `??`, `{}?`), they become nongreedy and start by -matching as little as possible, matching more only when the remaining -pattern does not fit the smaller match. - -And that is exactly what we want in this case. By having the star -match the smallest stretch of characters that brings us to a `*/`, -we consume one block comment and nothing more. +character)))(((empty set)))(((block comment)))(((line comment)))La parte anterior al operador `_or_` (o) simplemente hace coincidir dos caracteres de barra diagonal seguidos de cualquier número de caracteres de no-nueva-línea. La parte para comentarios multilínea está más involucrada. Utilizamos `_[^]_` (cualquier carácter que no esté en el conjunto vacío de caracteres) como una forma de coincidir con cualquier carácter. No podemos usar un punto aquí porque los comentarios de bloque pueden continuar en una nueva línea y los puntos no coinciden con el carácter de nueva-línea. + +Pero la salida del ejemplo anterior parece funcionar mal. ¿Por qué? + +(((backtracking)))(((greed)))(((regular expression)))La parte `_[^]*_` de la expresión, tal como describí en la sección de retroceso, se ajustará primero tanto como pueda. Si esto hace que la siguiente parte del patrón falle, el _matcher_ retrocede un carácter e intenta de nuevo desde allí. En el ejemplo, el primero busca coincidir con todo el resto de la cadena (_string_) y luego retrocede desde allí. Encontrará una instancia de `_*/_` después de volver cuatro caracteres y emparejar eso. Esto no es lo que queríamos: la intención era hacer coincidir un solo comentario, no ir hasta el final del código y encontrar el final del último comentario de bloque. + +Debido a este comportamiento, decimos que los operadores de repetición (`_+_`, `_*_`, `_?_`, y `_{}_`) son codiciosos, lo que significa que coinciden tanto como pueden y retroceden desde allí. Si lo combinas con un signo de interrogación (`_+?_`, `_*?_`, `_??_`, `_{}_`?), pierden su codicia y empiezan por coincidir lo menos posible, _matcheando_ más sólo cuando el patrón restante no encaja en el _match_ más pequeño. + +Y eso es exactamente lo que queremos en este caso. Al tener `_*_` coincidir con la menor extensión de caracteres que nos lleve a un `_*/_`, consumimos un comentario de bloque y nada más. // test: wrap @@ -769,23 +483,14 @@ console.log(stripComments("1 /* a */+/* b */ 1")); // → 1 + 1 ---- -A lot of ((bug))s in ((regular expression)) programs can be traced to -unintentionally using a greedy operator where a nongreedy one would -work better. When using a ((repetition)) operator, consider the -nongreedy variant first. +Una gran cantidad de errores ((_bug_)) en los programas de expresión regular se puede detectar al comprobar el uso indebido de este comportamiento codicioso de un operador de repetición. Cuando utilice un operador de repetición, considere primero la variante de cambiar su comportamiento con `_?_`. -== Dynamically creating RegExp objects == +== Creación dinámica de objetos RegExp == (((regular expression,creation)))(((underscore character)))(((RegExp -constructor)))There are cases where you might not know the exact -((pattern)) you need to match against when you are writing your code. -Say you want to look for the user's name in a piece of text and -enclose it in underscore characters to make it stand out. Since you -will know the name only once the program is actually running, you -can't use the slash-based notation. +constructor)))Hay casos en los que puede que no conozca el patrón exacto que necesita para _matchear_ en el momento que está escribiendo su código. Digamos que desea buscar el nombre del usuario en un fragmento de texto y adjuntarlo en caracteres de subrayado para que se destaque. Dado que sabrá el nombre sólo una vez que el programa se esté ejecutando, no podrá utilizar la notación basada en barras. -But you can build up a string and use the `RegExp` ((constructor)) on -that. Here's an example: +Pero puede construir una cadena y usar el constructor `_RegExp_`. He aquí un ejemplo: [source,javascript] ---- @@ -796,23 +501,12 @@ console.log(text.replace(regexp, "_$1_")); // → _Harry_ is a suspicious character. ---- -(((regular expression,flags)))(((backslash character)))When creating -the `\b` ((boundary)) markers, we have to use two backslashes because -we are writing them in a normal string, not a slash-enclosed regular -expression. The second argument to the `RegExp` constructor contains -the options for the regular expression—in this case `"gi"` for global -and case-insensitive. +(((regular expression,flags)))(((backslash character)))Al crear los `_\b_` ((_boundary_)) marcadores de frontera, tenemos que usar dos barras invertidas porque las estamos escribiendo en una cadena normal, no una expresión regular con barra inclinada. El segundo argumento para el constructor `_RegExp_` contiene las opciones para la expresión regular, en este caso `_"gi"_` para global y sin distinción entre mayúsculas y minúsculas. -But what if the name is `"dea+hl[]rd"` because our user is a ((nerd))y -teenager? That would result in a nonsensical regular expression, which -won't actually match the user's name. +¿Pero qué ocurre si el nombre es `_"dea+hl[]rd"_`, un nombre posble si nuestro usuario es un ((nerd)) adolescente? Esto daría lugar a una expresión regular absurda, que no coincidirá con el nombre del usuario. (((backslash character)))(((escaping,in regexps)))(((regular -expression,escaping)))To work around this, we can add backslashes -before any character that we don't trust. Adding backslashes before -alphabetic characters is a bad idea because things like `\b` and `\n` -have a special meaning. But escaping everything that's not -alphanumeric or ((whitespace)) is safe. +expression,escaping)))Para evitar esto, podemos agregar barras inversas antes de cualquier carácter en el que no confiamos. Agregar barras invertidas antes de caracteres alfabéticos es una mala idea porque cosas como `_\b_` y `_\n_` tienen un significado especial. Pero escapar de todo lo que no es alfanumérico o espacio en blanco es seguro. [source,javascript] ---- @@ -824,14 +518,10 @@ console.log(text.replace(regexp, "_$1_")); // → This _dea+hl[]rd_ guy is super annoying. ---- -== The search method == +== El método search (búsqueda) == (((searching)))(((regular expression,methods)))(((indexOf -method)))(((search method)))The `indexOf` method on strings cannot be -called with a regular expression. But there is another method, -`search`, which does expect a regular expression. Like `indexOf`, it -returns the first index on which the expression was found, or -1 when -it wasn't found. +method)))(((search method)))El método `_indexOf_` de cadenas no se puede llamar desde una expresión regular. Pero hay otro método, `_search_`, que se puede invocar en una expresión regular. Al igual que `_indexOf_`, devuelve el primer índice en el que se encontró la expresión o devolverá _-1_ si no encontró nada. [source,javascript] ---- @@ -841,30 +531,18 @@ console.log(" ".search(/\S/)); // → -1 ---- -Unfortunately, there is no way to indicate that the match should start -at a given offset (like we can with the second argument to `indexOf`), -which would often be useful. +Desafortunadamente, no hay manera de indicar que el _matcheo_ comience en un determinado indice (como si podemos hacerlo con el segundo argumento en `_indexOf_`). -== The lastIndex property == +== La propiedad lastIndex == -(((exec method)))(((regular expression)))The `exec` method similarly -does not provide a convenient way to start searching from a given -position in the string. But it does provide an __in__convenient way. +(((exec method)))(((regular expression)))El método `_exec_` tampoco proporciona una manera comoda de iniciar una búsqueda desde una posición dada en la cadena, pero al menos si proporciona una manera incómoda de hacerlo. (((regular expression,matching)))(((matching)))(((source -property)))(((lastIndex property)))Regular expression objects have -properties. One such property is `source`, which contains the string -that expression was created from. Another property is `lastIndex`, -which controls, in some limited circumstances, where the next match -will start. +property)))(((lastIndex property)))Los objetos de expresión regular tienen propiedades. Una de estas propiedades es `_source_`, que contiene la cadena original de la que se creó la expresión. Otra propiedad es `_lastIndex_`, que controla, solo en algunas circunstancias, donde se iniciará la próxima partida. + (((interface,design)))(((exec method)))(((regular -expression,global)))Those circumstances are that the regular -expression must have the global (`g`) option enabled, and the match -must happen through the `exec` method. Again, a more sane solution -would have been to just allow an extra argument to be passed to -`exec`, but sanity is not a defining characteristic of JavaScript's -regular expression interface. +expression,global)))Esas circunstancias son que la expresión regular debe tener activada la opción global (`_g_`), y la coincidencia debe pasar a través del método `_exec_`. Una vez más, una solución más lógica habría sido simplemente permitir que un argumento extra fuera pasado a `_exec_`, pero la cordura no es una característica de la interfaz de expresión regular de JavaScript. [source,javascript] ---- @@ -877,16 +555,9 @@ console.log(pattern.lastIndex); // → 5 ---- -(((side effect)))(((lastIndex property)))If the match was successful, -the call to `exec` automatically updates the `lastIndex` property to -point after the match. If no match was found, `lastIndex` is set back -to zero, which is also the value it has in a newly constructed regular -expression object. +(((side effect)))(((lastIndex property)))Si el resultado fue satisfactorio, la llamada a `_exec_` actualiza automáticamente la propiedad `_lastIndex_` para apuntar después de la coincidencia. Si no se encontró ninguna coincidencia, `_lastIndex_` se pone de nuevo a cero, que es también el valor que tiene en un objeto de expresión regular de nueva construcción. -(((bug)))When using a global regular expression value for multiple -`exec` calls, these automatic updates to the `lastIndex` property can -cause problems. Your regular expression might be accidentally starting -at an index that was left over from a previous call. +(((bug)))Cuando se utiliza un valor de expresión regular global para varias llamadas `_exec_`, estas actualizaciones automáticas a la propiedad `_lastIndex_` pueden causar problemas. Su expresión regular podría iniciarse accidentalmente en un índice que quedó de una llamada anterior. [source,javascript] ---- @@ -897,12 +568,7 @@ console.log(digit.exec("and now: 1")); // → null ---- -(((regular expression,global)))(((match method)))Another interesting -effect of the global option is that it changes the way the `match` -method on strings works. When called with a global expression, instead -of returning an array similar to that returned by `exec`, `match` will -find _all_ matches of the pattern in the string and return an array -containing the matched strings. +(((regular expression,global)))(((match method)))Otro efecto interesante de la opción global es que cambia la forma en que funciona el método de coincidencia en cadenas (`_match_`). Cuando se llama con una expresión global, en lugar de devolver una matriz similar a la devuelta por `_exec_`, `_match_` encontrará todas las coincidencias del patrón en la cadena y devuelve una matriz que contiene las cadenas coincidentes. [source,javascript] ---- @@ -910,17 +576,11 @@ console.log("Banana".match(/an/g)); // → ["an", "an"] ---- -So be cautious with global regular expressions. The cases where they -are necessary—calls to `replace` and places where you want to -explicitly use ++lastIndex++—are typically the only places where you -want to use them. +Así que tenga cuidado con las expresiones regulares globales. Los casos en los que son necesarios (las llamadas a `_replace_` y los lugares donde se desea utilizar explícitamente `_lastIndex_`) suelen ser los únicos lugares donde debería utilizarlos. -=== Looping over matches === +=== Bucle de matchs === -(((lastIndex property)))(((exec method)))(((loop)))A common pattern is -to scan through all occurrences of a pattern in a string, in a way -that gives us access to the match object in the loop body, by using -`lastIndex` and `exec`. +(((lastIndex property)))(((exec method)))(((loop)))Un patrón común es escanear todas las instancias de un patrón en una cadena, de una manera que nos da acceso al objeto de coincidencia en el cuerpo del bucle, usando `_lastIndex_` y `_exec_`. [source,javascript] ---- @@ -934,23 +594,12 @@ while (match = number.exec(input)) // Found 88 at 40 ---- -(((while loop)))(((= operator)))This makes use of the fact that the -value of an ((assignment)) expression (`=`) is the assigned value. So -by using `match = number.exec(input)` as the condition in the `while` -statement, we perform the match at the start of each iteration, save -its result in a ((variable)), and stop looping when no more matches -are found. +(((while loop)))(((= operator)))Esto hace uso del hecho de que el valor de una expresión de asignación (`_=_`) es el valor asignado. Por lo tanto, utilizando `_match = number.exec(input)_` como condición en la sentencia `_while_`, realizamos la coincidencia al comienzo de cada iteración, guardamos su resultado en una ((variable)) y detenemos el bucle (_loop_) cuando no se encuentran más coincidencias. [[ini]] -== Parsing an INI file == +== Análisis de un archivo INI == -(((comment)))(((file format)))(((enemies example)))(((ini file)))To -conclude the chapter, we'll look at a problem that calls for ((regular -expression))s. Imagine we are writing a program to automatically -harvest information about our enemies from the ((Internet)). (We will -not actually write that program here, just the part that reads the -((configuration)) file. Sorry to disappoint.) The configuration file -looks like this: +(((comment)))(((file format)))(((enemies example)))(((ini file)))Para concluir el capítulo, veremos un problema que requiere expresiones regulares. Imagina que estamos escribiendo un programa para recolectar automáticamente información sobre nuestros enemigos desde ((Internet)). (En realidad, no escribiremos ese programa aquí, solo la parte que lee el archivo de configuración. Sentimos decepcionarlo.) El archivo de configuración se verá así: [source,text/plain] ---- @@ -970,32 +619,19 @@ type=evil sorcerer outputdir=/home/marijn/enemies/gargamel ---- -(((grammar)))The exact rules for this format (which is actually a -widely used format, usually called an _INI_ file) are as follows: +(((grammar)))Las reglas exactas para este formato (que en realidad es un formato ampliamente utilizado, generalmente llamado archivo INI) son las siguientes: -- Blank lines and lines starting with semicolons are ignored. +- Las líneas en blanco y líneas que comienzan con punto y coma son ignoradas. -- Lines wrapped in `[` and `]` start a new ((section)). +- Líneas envueltas en llaves (_[]_) inician una nueva sección. -- Lines containing an alphanumeric identifier followed by an `=` - character add a setting to the current section. +- Las líneas que contienen un identificador alfanumérico seguido de un carácter = añaden una configuración a la sección actual. -- Anything else is invalid. +- Cualquier otra cosa es inválida. -Our task is to convert a string like this into an array of objects, -each with a `name` property and an array of settings. We'll need one -such object for each section and one for the global settings at the -top. +Nuestra tarea es convertir una cadena como ésta en una matriz de objetos, cada uno con una propiedad `_name_` y una matriz de configuraciones. Necesitaremos un objeto para cada sección y otro para la configuración global en la parte superior. -(((carriage return)))(((line break)))(((newline character)))Since the -format has to be processed ((line)) by line, splitting up the file -into separate lines is a good start. We used `string.split("\n")` to -do this in link:06_object.html#split[Chapter 6]. Some operating -systems, however, use not just a newline character to separate lines -but a carriage return character followed by a newline (`"\r\n"`). -Given that the `split` method also allows a regular expression as its -argument, we can split on a regular expression like `/\r?\n/` to split -in a way that allows both `"\n"` and `"\r\n"` between lines. +(((carriage return)))(((line break)))(((newline character)))Dado que el formato tiene que ser procesado línea por línea, dividir el archivo en líneas separadas es un buen comienzo. No obstante, algunos sistemas operativos utilizan no sólo un carácter de nueva línea para separar líneas, sino un carácter de retorno de carro seguido de una nueva línea (`_"\r\n"_`). Dado que el método `_split_` también permite que una expresión regular sea su argumento, podemos dividir en una expresión regular como `_/\r?\n/_` para dividir de una manera que permita tanto `_"\n"_` como `_"\r\n"_` entre líneas. [source,javascript] ---- @@ -1023,155 +659,83 @@ function parseINI(string) { } ---- -(((parseINI function)))(((parsing)))This code goes over every line in -the file, updating the “current section” object as it goes along. -First, it checks whether the line can be ignored, using the expression -`/^\s*(;.*)?$/`. Do you see how it works? The part between the -((parentheses)) will match comments, and the `?` will make sure it -also matches lines containing only whitespace. - -If the line is not a ((comment)), the code then checks whether the -line starts a new ((section)). If so, it creates a new current section -object, to which subsequent settings will be added. - -The last meaningful possibility is that the line is a normal setting, -which the code adds to the current section object. - -If a ((line)) matches none of these forms, the function throws an -error. - -(((caret character)))(((dollar sign)))(((boundary)))Note the recurring -use of `^` and `$` to make sure the expression matches the whole line, -not just part of it. Leaving these out results in code that mostly -works but behaves strangely for some input, which can be a difficult -bug to track down. - -(((if keyword)))(((assignment)))(((= operator)))The pattern `if (match -= string.match(...))` is similar to the trick of using an assignment -as the condition for `while`. You often aren't sure that your call to -`match` will succeed, so you can access the resulting object only -inside an `if` statement that tests for this. To not break the -pleasant chain of `if` forms, we assign the result of the match to a -variable and immediately use that assignment as the test in the `if` -statement. - -== International characters == - -(((internationalization)))(((Unicode)))(((regular -expression,internationalization)))Because of JavaScript's initial -simplistic implementation and the fact that this simplistic approach -was later set in stone as ((standard)) behavior, JavaScript's regular -expressions are rather dumb about characters that do not appear in the -English language. For example, as far as JavaScript's regular -expressions are concerned, a “((word character))” is only one of the -26 characters in the Latin alphabet (uppercase or lowercase) and, for -some reason, the underscore character. Things like _é_ or _β_, which -most definitely are word characters, will not match `\w` (and _will_ -match uppercase `\W`, the nonword category). - -(((whitespace)))By a strange historical accident, `\s` (whitespace) -does not have this problem and matches all characters that the -Unicode standard considers whitespace, including things like the -((nonbreaking space)) and the ((Mongolian vowel separator)). - -(((character category)))Some ((regular expression)) -((implementation))s in other programming languages have syntax to -match specific ((Unicode)) character categories, such as “all -uppercase letters”, “all punctuation”, or “control characters”. There -are plans to add support for such categories JavaScript, but it -unfortunately looks like they won't be realized in the near ((future)). +(((parseINI function)))(((parsing)))Este código pasa por todas las líneas del archivo, actualizando el objeto "_currentSection_" a medida que avanza. En primer lugar, comprueba si la línea se puede ignorar, utilizando la expresión `_/^\s*(;.*)?$/_`. ¿Ves cómo funciona? La parte entre los paréntesis coincidirá con los comentarios, y el signo `_?_` se asegurará de que también coincida con las líneas que contienen sólo espacios en blanco. + +Cuando la línea no es un comentario, el código comprueba si la línea inicia una nueva sección. Si es así, crea un nuevo objeto de sección actual, al que se añadirán los ajustes siguientes. + +La última posibilidad significativa es que la línea es un ajuste normal, por lo que nuestro código lo agregará al objeto de sección actual. + +Si una línea no coincide con ninguno de estos formularios, la función produce un error. + +(((caret character)))(((dollar sign)))(((boundary)))Tenga en cuenta el uso recurrente de `_^_` y `_$_` para asegurarse de que la expresión coincide con toda la línea, no sólo parte de ella. Dejando estos resultados en código que funciona sobre todo, pero se comporta extrañamente para algunos tipos de _input_, lo que puede originar un error difícil de rastrear. + +(((if keyword)))(((assignment)))(((= operator)))El patrón `_if (match = string.match(...))_` es similar al truco de usar una asignación como condición para `_while_`. A menudo no estaremos seguros de que nuestra llamada a `_matchear_` tendrá éxito, por lo que se puede acceder al objeto resultante sólo dentro de una instrucción if que las pruebas de ello. Para no romper la agradable cadena que forma la sentencia `_if_`, asignamos el resultado de la coincidencia a una variable e inmediatamente utilizamos esa asignación como el `_test_` en la sentencia `_if_`. + +== Caracteres internacionales == + +(((internationalization)))(((Unicode)))(((regular expression,internationalization)))Debido a la implementación simplista inicial de JavaScript y al hecho de que este enfoque se estableció como base del comportamiento estándar, las expresiones regulares de JavaScript son bastante torpes acerca de los caracteres que no aparecen en el idioma inglés. Por ejemplo, en lo que se refiere a las expresiones regulares de JavaScript, un "_carácter para texto_" (_word character_) es sólo uno de los 26 caracteres del alfabeto latino (mayúsculas o minúsculas) y, por alguna razón, el carácter underscore (_). Caracteres como _é_ o _β_, que definitivamente son _caracteres de texto_, no coincidirán con `_\w_` (y coincidirán con `_\W_`, carácter para no texto (_nonword category_)). + +(((whitespace)))Por un extraño accidente histórico, `_\s_` (espacio en blanco) no tiene este problema y coincide con todos los caracteres que el estándar _Unicode_ considera espacios en blanco, incluyendo cosas como el espacio no separable y el separador de vocales mongol. + +(((character category)))Algunas implementaciones de expresiones regulares en otros lenguajes de programación tienen sintaxis para coincidir con categorías de caracteres Unicode específicas, como "todas las letras mayúsculas", "todos los signos de puntuación" o "caracteres de control". Hay planes para agregar soporte para JavaScript de estas categorías, pero por desgracia parece que no en un futuro próximo. [[summary_regexp]] -== Summary == +== Resumen == -Regular expressions are objects that represent patterns in strings. -They use their own syntax to express these patterns. +Las expresiones regulares son objetos que representan patrones en cadenas. Utilizan su propia sintaxis para expresar estos patrones. [cols="1,5"] |==== -|`/abc/` |A sequence of characters -|`/[abc]/` |Any character from a set of characters -|`/[^abc]/` |Any character _not_ in a set of characters -|`/[0-9]/` |Any character in a range of characters -|`/x+/` |One or more occurrences of the pattern `x` -|`/x+?/` |One or more occurrences, nongreedy -|`/x*/` |Zero or more occurrences -|`/x?/` |Zero or one occurrence -|`/x{2,4}/` |Between two and four occurrences -|`/(abc)/` |A group -|++/a{brvbar}b{brvbar}c/++ |Any one of several patterns -|`/\d/` |Any digit character -|`/\w/` |An alphanumeric character (“word character”) -|`/\s/` |Any whitespace character -|`/./` |Any character except newlines -|`/\b/` |A word boundary -|`/^/` |Start of input -|`/$/` |End of input +|`/abc/` |Una secuencia de caracteres +|`/[abc]/` |Cualquier carácter en un conjunto de caracteres +|`/[^abc]/` |Cualquier carácter que no este en un conjunto de caracteres +|`/[0-9]/` |Cualqier carácter en un rango de caracteres +|`/x+/` |Una o mas ocurrencias del patron `x` +|`/x+?/` |Una o mas ocurrencias, no codiciosos +|`/x*/` |Cero o mas ocurrencias +|`/x?/` |Cero o una ocurrencia +|`/x{2,4}/` |Entre dos o cuatro ocurrencias +|`/(abc)/` |Un grupo +|++/a{brvbar}b{brvbar}c/++ |Cualqiera de estos patrones +|`/\d/` |Cualquier carácter digital +|`/\w/` |Cualquier carácter alfanúmerico (“word character”) +|`/\s/` |Cualquier carácter de espacio en blanco +|`/./` |Cualquier carácter excepto nuevas líneas +|`/\b/` |Limite de palabra +|`/^/` |Inicio de la entrada +|`/$/` |Fin de la entrada |==== -A regular expression has a method `test` to test whether a given -string matches it. It also has an `exec` method that, when a match is -found, returns an array containing all matched groups. Such an array -has an `index` property that indicates where the match started. - -Strings have a `match` method to match them against a regular -expression and a `search` method to search for one, returning only the -starting position of the match. Their `replace` method can replace -matches of a pattern with a replacement string. Alternatively, you can -pass a function to `replace`, which will be used to build up a -replacement string based on the match text and matched groups. - -Regular expressions can have options, which are written after -the closing slash. The `i` option makes the match case insensitive, -while the `g` option makes the expression _global_, which, among other -things, causes the `replace` method to replace all instances instead -of just the first. - -The `RegExp` constructor can be used to create a regular expression -value from a string. - -Regular expressions are a sharp ((tool)) with an awkward handle. They -simplify some tasks tremendously but can quickly become unmanageable -when applied to complex problems. Part of knowing how to use them is -resisting the urge to try to shoehorn things that they cannot sanely -express into them. - -== Exercises == - -(((debugging)))(((bug)))It is almost unavoidable that, in the course -of working on these exercises, you will get confused and frustrated by -some regular expression's inexplicable ((behavior)). Sometimes it -helps to enter your expression into an online tool like -https://www.debuggex.com/[_debuggex.com_] to see whether its -visualization corresponds to what you intended and to ((experiment)) -with the way it responds to various input strings. +Una expresión regular tiene un método `_test_` para comprobar si una cadena dada tiene coincidencias con ella. También tiene un método `_exec_` que, cuando se encuentra una coincidencia, devuelve una matriz que contiene todos los grupos coincidentes. Dicha matriz tiene una propiedad de índice (`_index_`) que indica dónde se inició la coincidencia. + +Las cadenas tienen un método `_match_` para buscar coincidencia con una expresión regular y un método `_search_` para realizar busquedas, que devuelve sólo la posición inicial de la coincidencia. El método `_replace_` puede reemplazar las coincidencias (los _matcheos_) de un patrón con una cadena de reemplazo. Como alternativa puedes crear una función `_replace_`, y así crear una cadena de reemplazo basada en el texto de coincidencia y los grupos coincidentes. + +Las expresiones regulares pueden tener opciones, que se escriben después de la barra de cierre (_|_). La opción `_i_` hace que el _matcheo_ sea insensible a mayusculas y minusculas (case insensitive), mientras que la opción `_g_` hace que la expresión sea global, eso genera, entre otras cosas, hace que el método _replace_ reemplace todas las instancias en lugar de sólo la primera. + +El constructor `_RegExp_` se puede utilizar para crear un valor de expresión regular a partir de una cadena. + +Las expresiones regulares son una herramienta muy afilada con un comando torpe. Ello simplifican algunas tareas pero pueden volverse incontrolables cuando se aplican a problemas complejos. Parte de saber cómo usarlos es resistir el impulso de intentar utilizarlas en los casos incorrectos. + +== Ejercicios == + +(((debugging)))(((bug)))Es casi inevitable que cuando haga estos ejercicios, se confunda y se frustre por el comportamiento inexplicable de alguna expresión regular. A veces, ayuda a introducir su expresión en una herramienta en línea como https://www.debuggex.com/[_debuggex.com_] para ver si su solución corresponde con lo que usted buscaba y experimentar con la forma en que ésta responde a distintas cadenas. === Regexp golf === (((program size)))(((code golf)))(((regexp golf (exercise))))_Code -golf_ is a term used for the game of trying to express a particular -program in as few characters as possible. Similarly, _regexp golf_ is -the practice of writing as tiny a regular expression as possible to -match a given pattern, and _only_ that pattern. - -(((boundary)))(((matching)))For each of the following items, write a ((regular -expression)) to test whether any of the given substrings occur in a -string. The regular expression should match only strings containing -one of the substrings described. Do not worry about word boundaries -unless explicitly mentioned. When your expression works, see whether you -can make it any smaller. +golf_ es un término usado en un juego que busca expresar un programa determinado en la mínima cantidad de caracteres posible. Del mismo modo, _regexp golf_ es la práctica de escribir una expresión regular tan pequeña como sea posible para que coincida con un patrón dado, y sólo ese patrón. + +(((boundary)))(((matching)))Para cada uno de los siguientes elementos, escriba una expresión regular que compruebe si alguna de las subcadenas se produce en una cadena. La expresión regular debe coincidir sólo con cadenas que contengan una de las subcadenas descritas. No se preocupe por los límites de palabras a menos que se mencionen explícitamente. Cuando logre que su expresión funcione, vea si puede lograr reducir la expresión. 1. _car_ and _cat_ 2. _pop_ and _prop_ - 3. _ferret_, _ferry_, and _ferrari_ - 4. Any word ending in _ious_ - 5. A whitespace character followed by a dot, comma, colon, or semicolon - 6. A word longer than six letters - 7. A word without the letter _e_ + 3. _ferret_, _ferry_, y _ferrari_ + 4. Cualquier palabra que termine en _ious_ + 5. Un carácter de espacio en blanco seguido de un punto, coma, dos puntos o punto y coma + 6. Una palabra de más de seis letras + 7. Una palabra sin la letra _e_ -Refer to the table in the -link:09_regexp.html#summary_regexp[chapter summary] for help. Test each -solution with a few test strings. +Consulte la tabla del link:09_regexp.html#summary_regexp[resumen del capítulo] para obtener ayuda. Pruebe cada solución con unas cuantas cadenas de prueba. ifdef::interactive_target[] [source,javascript] @@ -1222,18 +786,12 @@ function verify(regexp, yes, no) { ---- endif::interactive_target[] -=== Quoting style === +=== Estilo de citas === (((quoting style (exercise))))(((single-quote -character)))(((double-quote character)))Imagine you have written a -story and used single ((quotation mark))s throughout to mark pieces -of dialogue. Now you want to replace all the dialogue quotes with -double quotes, while keeping the single quotes used in contractions -like _aren't_. +character)))(((double-quote character)))Imagine que ha escrito una historia en Ingles y ha usado comillas simples para marcar partes del diálogo. Ahora desea reemplazar todas las citas de diálogo con comillas dobles, manteniendo las comillas simples que se usan en contracciones. -(((replace method)))Think of a pattern that distinguishes these two -kinds of quote usage and craft a call to the `replace` method that -does the proper replacement. +(((replace method)))Piense en un patrón que distinga estos dos tipos de comillado y cree una llamada al método `_replace_` que haga la sustitución adecuada. ifdef::interactive_target[] // test: no @@ -1247,36 +805,19 @@ console.log(text.replace(/A/g, "B")); ---- endif::interactive_target[] -!!hint!! +!!pista!! -(((quoting style (exercise))))(((boundary)))The most obvious solution -is to only replace quotes with a nonword character on at least one -side. Something like `/\W'|'\W/`. But you also have to take the start -and end of the line into account. +(((quoting style (exercise))))(((boundary)))La solución más obvia es reemplazar las citas con un carácter sin palabras al menos en uno de los lados. Algo como `_/\W'|'\W/_`, pero también tenga en cuenta el principio y el final de cada línea. -(((grouping)))(((replace method)))In addition, you must ensure that -the replacement also includes the characters that were matched by the -`\W` pattern so that those are not dropped. This can be done by -wrapping them in ((parentheses)) and including their groups in the -replacement string (`$1`, `$2`). Groups that are not matched will be -replaced by nothing. +(((grouping)))(((replace method)))Además, debe asegurarse de que el reemplazo también incluya los caracteres que coincidan con el patrón `_\W_` para que no se eliminen. Esto se puede hacer envolviéndolos entre paréntesis e incluyendo sus grupos en la cadena de reemplazo (`_$1_`, `_$2_`). Los grupos que no coincidan serán reemplazados por nada. -!!hint!! +!!pista!! === Numbers again === -(((number)))A series of ((digit))s can be matched by the simple -regular expression `/\d+/`. +(((number)))Una serie de dígitos puede ser igualada por la expresión regular simple `_/\d+/_`. -(((sign)))(((fractional number)))(((syntax)))(((minus)))(((plus -character)))(((exponent)))(((scientific notation)))(((period -character)))Write an expression that matches only JavaScript-style -numbers. It must support an optional minus _or_ plus sign in front of -the number, the decimal dot, and exponent notation—`5e-3` or ++1E10++— -again with an optional sign in front of the exponent. Also note that -it is not necessary for there to be digits in front of or after the -dot, but the number cannot be a dot alone. That is, `.5` and `5.` -are valid JavaScript numbers, but a lone dot _isn't_. +(((sign)))(((fractional number)))(((syntax)))(((minus)))(((plus character)))(((exponent)))(((scientific notation)))(((period character)))Escriba una expresión que coincida sólo con los números válidos para JavaScript. Debe soportar un signo positivo o negativo adicional delante del número, el punto decimal y la notación de exponente `_5e-3_` o ++_1E10_++- tambien con la opcion de un signo delante del exponente. Observe también que no es necesario que haya dígitos delante o después del punto, pero el número no puede ser solamente un punto, es decir, `_.5_` y `_5._` son números JavaScript válidos, pero un punto solitario no lo es.Write an expression that matches only JavaScript-style ifdef::interactive_target[] // test: no @@ -1300,24 +841,15 @@ var number = /^...$/; ---- endif::interactive_target[] -!!hint!! +!!pista!! -(((regular expression,escaping)))(((backslash character)))First, do -not forget the backslash in front of the dot. +(((regular expression,escaping)))(((backslash character)))En primer lugar, no se olvide de la barra invertida delante del punto. -Matching the optional ((sign)) in front of the ((number)), as well as -in front of the ((exponent)), can be done with `[+\-]?` or `(\+|-|)` -(plus, minus, or nothing). +Se puede hacer coincidir el signo opcional delante del número, así como delante del exponente, con `_[+\-]?_` o `_(\+|-|)_` (más, menos o nada). -(((pipe character)))The more complicated part of the exercise is the -problem of matching both `"5."` and `".5"` without also matching -`"."`. For this, a good solution is to use the `|` operator to -separate the two cases—either one or more digits optionally followed -by a dot and zero or more digits _or_ a dot followed by one or more -digits. +(((pipe character)))La parte más complicada del ejercicio es el problema de coincidir con `_"5."_` y `_".5"_` sin igualar también `_"."_` . Para ello, una buena solución es utilizar el operador `_|_` para separar los dos casos: uno o más dígitos opcionalmente seguido por un punto y cero o más dígitos o un punto seguido por uno o más dígitos. (((exponent)))(((case sensitivity)))(((regular -expression,flags)))Finally, to make the _e_ case-insensitive, either -add an `i` option to the regular expression or use `[eE]`. +expression,flags)))Por último, para que en el caso del carácter _e_ no distinga entre mayúsculas y minúsculas, agregue una opción `_i_` a la expresión regular o utilice `_[eE]_`. -!!hint!! +!!pista!! \ No newline at end of file diff --git a/11_language.txt b/11_language.txt index 4610f8310..48af68b29 100644 --- a/11_language.txt +++ b/11_language.txt @@ -4,13 +4,12 @@ :load_files: ["code/chapter/11_language.js"] :zip: node/html -= Project: A Programming Language = += Proyecto: Un lenguaje de programación = [chapterquote="true"] [quote, Hal Abelson and Gerald Sussman, Structure and Interpretation of Computer Programs] ____ -The evaluator, which determines the meaning of expressions in a -programming language, is just another program. +El evaluador, que determina el significado de las expresiones en un lenguaje de programación, es simplemente otro programa. ____ ifdef::interactive_target[] @@ -18,55 +17,30 @@ ifdef::interactive_target[] [chapterquote="true"] [quote, Master Yuan-Ma, The Book of Programming] ____ -When a student asked the master about the nature of the cycle of Data -and Control, Yuan-Ma replied ‘Think of a compiler, compiling itself.’ +Cuando un estudiante le preguntó al maestro acerca de la naturaleza del ciclo de datos y control, Yuan-Ma respondió "Piensa en un compilador, compilándose." ____ endif::interactive_target[] (((Abelson+++,+++ Hal)))(((Sussman+++,+++ -Gerald)))(((SICP)))(((project chapter)))Building your own -((programming language)) is surprisingly easy (as long as you do not -aim too high) and very enlightening. +Gerald)))(((SICP)))(((project chapter)))Construir su propio lenguaje de programación es sorprendentemente fácil (siempre y cuando no apunte demasiado alto) y muy esclarecedor. -The main thing I want to show in this chapter is that there is no -((magic)) involved in building your own language. I've often felt that -some human inventions were so immensely clever and complicated that -I'd never be able to understand them. But with a little reading and -tinkering, such things often turn out to be quite mundane. +Lo principal que quiero mostrar en este capítulo es que no hay ((magia)) involucrada en la construcción de su propio idioma. A menudo he sentido que algunas invenciones humanas eran tan inmensamente inteligentes y complicadas que nunca sería capaz de entenderlas. Pero con un poco de lectura y retoques, tales cosas a menudo resultan ser bastante mundano. -(((Egg language)))We will build a programming language called Egg. It -will be a tiny, simple language but one that is powerful enough to -express any computation you can think of. It will also allow simple -((abstraction)) based on ((function))s. +(((Egg language)))Construiremos un lenguaje de programación llamado "Egg". Será un lenguaje pequeño y sencillo, pero que sea lo suficientemente poderoso para expresar cualquier cálculo que se pueda imaginar. También permitirá la ((abstracción)) simple basada en ((funciones)). [[parsing]] -== Parsing == - -(((parsing)))(((validation)))The most immediately visible part of a -programming language is its _((syntax))_, or notation. A _parser_ is a -program that reads a piece of text and produces a data structure that -reflects the structure of the program contained in that text. If the -text does not form a valid program, the parser should complain and -point out the error. - -(((special form)))Our language will have a simple and uniform -syntax. Everything in Egg is an ((expression)). An expression can be a -variable, a number, a string, or an _application_. Applications are -used for function calls but also for constructs such as `if` or `while`. - -(((double-quote character)))(((parsing)))(((escaping,in strings)))To -keep the parser simple, strings in Egg do not support anything like -backslash escapes. A string is simply a sequence of characters that -are not double quotes, wrapped in double quotes. A number is a -sequence of digits. Variable names can consist of any character that -is not ((whitespace)) and does not have a special meaning in the -syntax. - -(((comma character)))Applications are written the way they are in -JavaScript, by putting ((parentheses)) after an expression and having -any number of ((argument))s between those parentheses, separated by -commas. +== Analizando == + +(((parsing)))(((validation)))La parte más inmediatamente visible de un lenguaje de programación es su ((sintaxis)), o notación. Un analizador es un programa que lee una parte del texto y produce una estructura de datos que refleja la estructura del programa contenido en ese texto. Si el texto no forma un programa válido, el analizador debe quejarse y señalar el error. + + +(((special form)))Nuestro lenguaje tendrá una sintaxis simple y uniforme. Todo en "Egg" es una expresión. Una expresión puede ser una variable, un número, una cadena o una aplicación. Las aplicaciones se utilizan para llamar a funciones, pero también para construcciones como `if` o `while`. + + +(((double-quote character)))(((parsing)))(((escaping,in strings)))Para mantener el analizador simple, las cadenas en "Egg" no soportan nada como escapes de barra invertida. Una cadena es simplemente una secuencia de caracteres que no son comillas dobles, envueltos en comillas dobles. Un número es una secuencia de dígitos. Los nombres de las variables pueden consistir en cualquier carácter que no sea un espacio en blanco y no tenga un significado especial en la sintaxis. + +(((comma character)))Las aplicaciones se escriben de la forma en que están en JavaScript, poniendo ((paréntesis)) después de una expresión pudiendo tener cualquier número de ((argumentos)) entre esos paréntesis, separados por comas. ---- do(define(x, 10), @@ -75,16 +49,9 @@ do(define(x, 10), print("small"))) ---- -(((block)))The ((uniformity)) of the ((Egg language)) means that -things that are ((operator))s in JavaScript (such as `>`) are normal -variables in this language, applied just like other ((function))s. And -since the ((syntax)) has no concept of a block, we need a `do` -construct to represent doing multiple things in sequence. +(((block)))La uniformidad del lenguaje "Egg" significa que las cosas que son ((operadores)) en JavaScript (como `>`) son variables normales en este lenguaje, aplicadas como otras ((funciones)). Y puesto que la ((sintaxis)) no tiene concepto de un bloque, necesitamos una construcción `do` para representar hacer varias cosas en secuencia. -(((type property)))(((parsing)))The ((data structure)) that the parser will -use to describe a program will consist of ((expression)) objects, each -of which has a `type` property indicating the kind of expression it is -and other properties to describe its content. +(((type property)))(((parsing)))La ((estructura de datos)) que el analizador utilizará para describir un programa consistirá en objetos de ((expresión)), cada uno de los cuales tiene una propiedad `type` que indica el tipo de expresión que es y otras propiedades para describir su contenido. (((identifier)))Expressions of type `"value"` represent literal strings or numbers. Their `value` property contains the string or number value @@ -95,7 +62,9 @@ represent applications. They have an `operator` property that refers to the expression that is being applied, and they have an `args` property that refers to an array of argument expressions. -The `>(x, 5)` part of the previous program would be represented like this: +(((identifier)))Las expresiones de tipo `"value"` representan cadenas literales o números. Su propiedad `value` contiene el valor de cadena o número que representan. Las expresiones del tipo "`word`" se utilizan para identificadores (nombres). Tales objetos tienen una propiedad de name que contiene una cadena con su nombre. Finalmente, las expresiones `"apply"` representan aplicaciones. Tienen una propiedad `operator` que hace referencia a la expresión que se está aplicando y tienen una propiedad `args` que hace referencia a una matriz con sus argumentos. + +La parte `>(x, 5)` del programa anterior se representa así: [source,application/json] ---- @@ -110,40 +79,19 @@ The `>(x, 5)` part of the previous program would be represented like this: ---- indexsee:[abstract syntax tree,syntax tree] -Such a ((data structure)) is called a _((syntax tree))_. If you -imagine the objects as dots and the links between them as lines -between those dots, it has a ((tree))like shape. The fact that -expressions contain other expressions, which in turn might contain -more expressions, is similar to the way branches split and split again. +Esta ((estructura de datos)) se llama un _((estructura de árbol))_. Si usted imagina los objetos como puntos y los enlaces entre ellos como líneas entre esos puntos, tiene una forma de ((árbol)). El hecho de que las expresiones contengan otras expresiones, que a su vez podrían contener más expresiones, es similar al modo en que las ramas se dividen y se dividen de nuevo. image::img/syntax_tree.svg[alt="The structure of a syntax tree",width="5cm"] -(((parsing)))Contrast this to the parser we wrote for the -configuration file format in link:09_regexp.html#ini[Chapter 9], which -had a simple structure: it split the input into lines and -handled those lines one at a time. There were only a few simple forms -that a line was allowed to have. - -(((recursion)))(((nesting,of expressions)))Here we must find a -different approach. Expressions are not separated into lines, and they -have a recursive structure. Application expressions _contain_ other -expressions. - -(((elegance)))Fortunately, this problem can be solved elegantly by -writing a parser function that is recursive in a way that reflects the -recursive nature of the language. - -(((parseExpression function)))(((syntax tree)))We define a function -`parseExpression`, which takes a string as input and returns an -object containing the data structure for the expression at the start -of the string, along with the part of the string left after parsing -this expression. When parsing subexpressions (the argument to an -application, for example), this function can be called again, yielding -the argument expression as well as the text that remains. This text -may in turn contain more arguments or may be the closing parenthesis -that ends the list of arguments. - -This is the first part of the parser: +(((parsing)))Compare esto con el analizador que escribimos para el formato de archivo de configuración en el link:09_regexp.html#ini[Capítulo 9], que tenía una estructura simple: dividió la entrada en líneas y manejó esas líneas una a la vez. Solamente permitia tener alguna forma simples en una linea. + +(((recursion)))(((nesting,of expressions)))Aquí debemos encontrar un enfoque diferente. Las expresiones no se separan en líneas y tienen una estructura recursiva. Las expresiones de la aplicación _contienen_ otras expresiones. + +(((elegance)))Afortunadamente, este problema se puede resolver elegantemente escribiendo una función recursiva en el analizador una manera que refleja la naturaleza recursiva de la lengua. + +(((parseExpression function)))(((syntax tree)))Definimos la función `parseExpression`, que toma una cadena como entrada y devuelve un objeto que contiene la estructura de datos para la expresión al principio de la cadena, junto con la parte de la cadena que queda después de analizar esta expresión. Al analizar las subexpresiones (el argumento a una aplicación, por ejemplo), esta función puede ser llamada de nuevo, dando la expresión del argumento, así como el texto que permanece. Este texto puede a su vez contener más argumentos o puede ser el paréntesis de cierre que termina la lista de argumentos. + +Esta es la primera parte del analizador: // include_code @@ -171,25 +119,11 @@ function skipSpace(string) { } ---- -(((skipSpace function)))Because Egg allows any amount of -((whitespace)) between its elements, we have to repeatedly cut the -whitespace off the start of the program string. This is what the -`skipSpace` function helps with. +(((skipSpace function)))Debido a que "Egg" permite cualquier cantidad de espacio en blanco entre sus elementos, tenemos que cortar repetidamente el espacio en blanco desde el inicio de la cadena del programa. Para esto nos ayuda la función `skipSpace`. -(((literal expression)))(((SyntaxError type)))After skipping any -leading space, `parseExpression` uses three ((regular expression))s to -spot the three simple (atomic) elements that Egg supports: strings, -numbers, and words. The parser constructs a different kind of data -structure depending on which one matches. If the input does not match -one of these three forms, it is -not a valid expression, and the parser throws an error. `SyntaxError` is a -standard error object type, which is raised when an attempt is made to -run an invalid JavaScript program. +(((literal expression)))(((SyntaxError type)))Después de salterse cualquier espacio en blanco, `parseExpression` utiliza tres expresiones regulares para detectar los tres elementos simples (atomic) que "Egg" soporta: cadenas, números y palabras. El analizador construye un tipo diferente de estructura de datos dependiendo de cuál coincide. Si la entrada no coincide con una de estas tres formas, no es una expresión válida y el analizador genera un error. `SyntaxError` es un tipo de objeto de error estándar, que se genera cuando se intenta ejecutar un programa no válido en JavaScript. -(((parseApply function)))We can then cut off the part that we matched -from the program string and pass that, along with the object for the -expression, to `parseApply`, which checks whether the expression is an -application. If so, it parses a parenthesized list of arguments. +(((parseApply function)))Podemos entonces cortar la parte que coincide con una cadena en el programa y pasar que, junto con el objeto de la expresión, a `parseApply`, que comprueba si la expresión es una aplicación. Si es así, analiza una lista de argumentos entre paréntesis. // include_code @@ -215,26 +149,18 @@ function parseApply(expr, program) { } ---- -(((parsing)))If the next character in the program is not an opening -parenthesis, this is not an application, and `parseApply` simply -returns the expression it was given. +(((parsing)))Si el siguiente carácter del programa no es un paréntesis de apertura, esto no es una aplicación y `parseApply` simplemente devuelve la expresión que se le dio. -(((recursion)))Otherwise, it skips the opening parenthesis and -creates the ((syntax tree)) object for this application expression. It -then recursively calls `parseExpression` to parse each argument until a -closing parenthesis is found. The recursion is indirect, through -`parseApply` and `parseExpression` calling each other. +(((recursion)))De lo contrario, omite el paréntesis de apertura y crea el objeto de ((estructura de árbol)) para esta expresión de aplicación. A continuación, recursivamente llama a `ParseExpression` para analizar cada argumento hasta que se encuentra un paréntesis de cierre. La recursión es indirecta, a través de `parseApply` y `parseExpression` llamándose entre sí. Because an application expression can itself be applied (such as in `multiplier(2)(1)`), `parseApply` must, after it has parsed an application, call itself again to check whether another pair of parentheses follows. -(((syntax tree)))(((Egg language)))(((parse function)))This is all we -need to parse Egg. We wrap it in a convenient `parse` function that -verifies that it has reached the end of the input string after parsing -the expression (an Egg program is a single expression), and that -gives us the program's data structure. +Porque una expresión de aplicación puede aplicarse por sí misma (como en `multiplier(2)(1)`), `parseApply` debe, después de haber analizado una aplicación, volver a llamar para comprobar si hay otro par de paréntesis. + +(((syntax tree)))(((Egg language)))(((parse function)))Esto es todo lo que necesita el analizador "Egg". Lo envolvemos en una conveniente función de análisis que verifica que ha llegado al final de la cadena de entrada después de analizar la expresión (un programa "Egg" es una sola expresión), y que nos da la estructura de datos del programa. // include_code strip_log // test: join @@ -255,19 +181,12 @@ console.log(parse("+(a, 10)")); // {type: "value", value: 10}]} ---- -(((error message)))It works! It doesn't give us very helpful -information when it fails and doesn't store the line and column on -which each expression starts, which might be helpful when reporting -errors later, but it's good enough for our purposes. +(((error message)))¡Funciona! No nos da información muy útil cuando falla y no almacena la línea y la columna en la que empieza cada expresión, lo que podría ser útil cuando se reportan errores más tarde, pero es lo suficientemente bueno para nuestros propósito. -== The evaluator == +== El evaluador == (((evaluate function)))(((evaluation)))(((interpretation)))(((syntax -tree)))(((Egg language)))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 an environment object that associates names -with values, and it will evaluate the expression that the tree -represents and return the value that this produces. +tree)))(((Egg language)))¿Qué podemos hacer con la estructura de árbol del programa? Correrla, por supuesto! Y eso es lo que hace el evaluador. Se le asigna una estructura de árbol y un objeto de entorno que asocia nombres con valores y evaluará la expresión que representa el árbol y devolverá el valor que produce. // include_code @@ -301,43 +220,20 @@ function evaluate(expr, env) { var specialForms = Object.create(null); ---- -(((literal expression)))(((environment)))The evaluator has code for -each of the ((expression)) types. A literal value expression simply -produces its value. (For example, the expression `100` just evaluates -to the number 100.) For a variable, we must check whether it is -actually defined in the environment and, if it is, fetch the -variable's value. +(((literal expression)))(((environment)))El evaluador tiene código para cada uno de los tipos de expresiones. Una expresión de valor literal simplemente produce su valor. (Por ejemplo, la expresión 100 equivale al número 100.) Para una variable, debemos comprobar si está realmente definida en el entorno y, si es así, buscar el valor de la variable. -(((function,application)))Applications are more involved. If they are -a ((special form)), like `if`, we do not evaluate anything and simply -pass the argument expressions, along with the environment, 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 -result of evaluating the arguments. +(((function,application)))Las aplicaciones están más comprometidas. Si son una forma especial, como `if`, no evaluamos nada y simplemente pasamos las expresiones de argumento, junto con el entorno, a la función que maneja esta estructura. Si es una llamada normal, evaluamos al operador, verificamos que es una función y lo llamamos con el resultado de evaluar los argumentos. -We will use plain JavaScript function values to represent Egg's -function values. We will come back to this -link:11_language.html#egg_fun[later], when the special form called -`fun` is defined. +Utilizaremos funciones simple de JavaScript para representar los valores de funciones de "Egg". Volveremos a esto link:11_language.html#egg_fun[más adelante], cuando definamos la forma especial de llamar funciones. (((readability)))(((evaluate -function)))(((recursion)))(((parsing)))The recursive structure of -`evaluate` resembles the similar structure of the parser. 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 more readable. +function)))(((recursion)))(((parsing)))La estructura recursiva de `evaluate` se asemeja a la estructura similar de `parse`. Ambos reflejan la estructura del lenguaje mismo. También sería posible integrar el `parse` con el `evaluate` y evaluar durante el análisis sintáctico, pero dividirlo de esta manera hace que el programa sea más legible. -(((Egg language)))(((interpretation)))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 anything with this language yet. +(((Egg language)))(((interpretation)))Esto es realmente todo lo que se necesita interpretar "Egg". Así de simple. Sin embargo, sin definir algunas formas especiales y agregar algunas utilidades al ((entorno)), todavía no se puede hacer nada con este lenguaje. == Special forms == -(((special form)))(((specialForms object)))The `specialForms` object -is used to define special syntax in Egg. It associates words with -functions that evaluate such special forms. It is currently empty. -Let's add some forms. +(((special form)))(((specialForms object)))El objeto `specialForms` se utiliza para definir sintaxis especial en "Egg". Asocia palabras con funciones que evalúan tales formas especiales. Actualmente está vacío. Añadamos algunas formas. // include_code @@ -354,25 +250,13 @@ specialForms["if"] = function(args, env) { }; ---- -(((conditional execution)))Egg's `if` 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. +(((conditional execution)))El Constructor `if` de "Egg" espera exactamente tres argumentos. Se evaluará el primero, y si el resultado no es el valor `false`, se evaluará el segundo. Si no, el tercero se evaluara. Esta forma es más similar a operador ternario `?:` que al de JavaScript `if`. Es una expresión, no una declaración, y produce un valor, es decir, el resultado del segundo o tercer argumento. -(((Boolean)))Egg 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, but only the precise value `false`. +(((Boolean)))"Egg" difiere de JavaScript en cómo maneja el valor de la condición `if`. No tratará las cosas como cero o la cadena vacía como `false`, sólo el valor preciso `false`. -(((short-circuit evaluation)))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. +(((short-circuit evaluation)))La razón por la que tenemos que representar `if` como una estructura especial, en lugar de una función regular, es que todos los argumentos a las funciones se evalúan antes de que se llame a la función, mientras que `if` debería evaluar sólo su segundo o su tercer argumento, dependiendo del valor del primero. -The `while` form is similar. +La estructura de `while` es similar. // include_code @@ -385,15 +269,13 @@ specialForms["while"] = function(args, env) { while (evaluate(args[0], env) !== false) evaluate(args[1], env); - // Since undefined does not exist in Egg, we return false, - // for lack of a meaningful result. + // Como undefined no existe en Egg, devolvemos false, + // para la falta de resultados válidos return false; }; ---- -Another basic building block is `do`, which executes all its arguments -from top to bottom. Its value is the value produced by the last -argument. +Otro bloque de construcción básico es `do`, que ejecuta todos sus argumentos de arriba a abajo. Su valor es el valor producido por el último argumento. // include_code @@ -408,12 +290,7 @@ specialForms["do"] = function(args, env) { }; ---- -(((= operator)))To be able to create ((variable))s and give them new -values, we also create a form called `define`. It expects a word as -its first argument and an expression producing the value to assign to -that word as its second argument. Since `define`, 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). +(((= operator)))Para poder crear variables y darles nuevos valores, también creamos una `specialForms` llamada `define`. Espera una palabra como su primer argumento y una expresión que produce el valor para asignar a esa palabra como su segundo argumento. Dado que `define`, como toda una expresión, debe devolver un valor. Vamos a hacer que devuelva el valor que se asignó (Como el operador `=` de JavaScript) // include_code @@ -428,18 +305,11 @@ specialForms["define"] = function(args, env) { }; ---- -== The environment == +== El entorno == -(((Egg language)))(((evaluate function)))The ((environment)) accepted -by `evaluate` is an object with properties whose names correspond to -variable names and whose values correspond to the values those -((variable))s are bound to. Let's define an environment object to -represent the ((global scope)). +(((Egg language)))(((evaluate function)))El ((entorno)) aceptado por el evaluador es un objeto con propiedades cuyos nombres corresponden a nombres de ((variables)) y cuyos valores corresponden a los valores a los que están vinculadas. Vamos a definir un objeto de entorno 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 variables to the values `true` and `false` and use those. +Para poder usar la construcción `if` que acabamos de definir, debemos tener acceso a valores ((booleanos)). Como sólo tiene dos valores, no necesitamos sintaxis especial para ellos. Simplemente enlazamos dos variables a los valores `true` y `false` y los usamos. // include_code @@ -451,7 +321,7 @@ topEnv["true"] = true; topEnv["false"] = false; ---- -We can now evaluate a simple expression that negates a Boolean value. +Ahora podemos evaluar un expresión y devolver un valor ((boleano)). [source,javascript] ---- @@ -460,11 +330,7 @@ console.log(evaluate(prog, topEnv)); // → false ---- -(((arithmetic)))(((Function constructor)))To supply basic -((arithmetic)) and ((comparison)) ((operator))s, we will also add some -function values to the ((environment)). In the interest of keeping the -code short, we'll use `new Function` to synthesize a bunch of operator -functions in a loop, rather than defining them all individually. +(((arithmetic)))(((Function constructor)))Para facilitar ((aritmética)) y ((operadores)) de ((comparación)), también agregaremos algunos valores de función al entorno. En interés de mantener el código corto, vamos a utilizar `new Function` para sintetizar un montón de funciones de operador en un bucle, en lugar de definir todos ellos individualmente. // include_code @@ -475,8 +341,7 @@ functions in a loop, rather than defining them all individually. }); ---- -A way to ((output)) values is also very useful, so we'll wrap -`console.log` in a function and call it `print`. +También es muy útiluna forma de mostrar valores de salida, así que vamos a envolver `console.log` en una función y lo llamamos `print`. // include_code @@ -488,10 +353,7 @@ topEnv["print"] = function(value) { }; ---- -(((parsing)))(((run function)))That gives us enough elementary tools -to write simple programs. The following `run` function provides a -convenient way to write and run them. It creates a fresh environment -and parses and evaluates the strings we give it as a single program. +(((parsing)))(((run function)))Eso nos da suficientes herramientas para escribir programas sencillos. La siguiente función `run` proporciona una forma conveniente de escribirlos y ejecutarlos. Crea un nuevo ámbito y analiza y evalúa las cadenas que le damos como un solo programa. // include_code @@ -505,11 +367,7 @@ function run() { } ---- -(((join method)))(((call method)))The use of -`Array.prototype.slice.call` is a trick to turn an ((array-like -object)), such as `arguments`, into a real array so that we can call -`join` on it. It takes all the arguments given to `run` and treats -them as the lines of a program. +(((join method)))(((call method)))El uso de `Array.prototype.slice.call` es un truco para convertir un objeto en array-like(similar o que se asemeja a un array), con tantos elementos como `arguments`, en una Array así que podemos llamar a `join`. Toma todos los `arguments` dados para ejecutarlos y los trata como las líneas de un programa. [source,javascript] ---- @@ -522,21 +380,14 @@ run("do(define(total, 0),", // → 55 ---- -(((summing example)))(((Egg language)))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)). +(((summing example)))(((Egg language)))Este es el programa que hemos visto varias veces antes, que calcula la suma de los números 1 a 10, expresada en "Egg". Es claramente más feo que el programa JavaScript equivalente, pero no está mal para un lenguaje implementado en menos de 150 ((líneas de código)). [[egg_fun]] -== Functions == +== Funciones == -(((function)))(((Egg language)))A programming language without -functions is a poor programming language indeed. +(((function)))(((Egg language)))Un lenguaje de programación sin funciones es un lenguaje verdaderamente pobre -Fortunately, it is not hard to add a `fun` construct, which treats its -last argument as the function's body and treats all the arguments before that as -the names of the function's arguments. +Afortunadamente, no es difícil añadir una constructor `fun`, que trata su último argumento como el cuerpo de la función y todos los argumentos anteriores como los nombres de los argumentos de la función. // include_code @@ -564,16 +415,9 @@ specialForms["fun"] = function(args, env) { }; ---- -(((local scope)))(((Object.create function)))(((prototype)))Functions -in Egg have their own local environment, just like in JavaScript. We -use `Object.create` to make a new object that has access to the -variables in the outer environment (its prototype) but that can also -contain new variables without modifying that outer scope. +(((local scope)))(((Object.create function)))(((prototype)))Las funciones en "Egg" tienen su propio entorno local, al igual que en JavaScript. Utilizamos `Object.create` para crear un nuevo objeto que tenga acceso a las variables del entorno externo (su prototipo) pero que también pueda contener nuevas variables sin modificar al ámbito global. -(((power example)))(((evaluation)))(((interpretation)))The function -created by the `fun` form creates this local environment and adds the -argument variables to it. It then evaluates the function body in this -environment and returns the result. +(((power example)))(((evaluation)))(((interpretation)))La función creada por el objecto `fun` crea este entorno local y le agrega las variables por argumentos. A continuación, evalúa el cuerpo de la función en este entorno y devuelve el resultado. // start_code @@ -591,65 +435,29 @@ run("do(define(pow, fun(base, exp,", // → 1024 ---- -== Compilation == +== Compilación == -(((interpretation)))(((compilation)))What we have built is an -interpreter. During evaluation, it acts directly on the representation -of the program produced by the parser. +(((interpretation)))(((compilation)))Lo que hemos construido es un intérprete. Durante la evaluación, actúa directamente sobre la representación del programa producido por el analizador. -(((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 -((variable)), which variable is being referred to, without actually -running the program. This can be used to avoid looking up the variable -by name every time it is accessed and to directly fetch it from some -predetermined ((memory)) location. +(((efficiency)))(((performance)))_Compilación_ es el proceso de añadir otro paso entre el análisis y el funcionamiento de un programa, que transforma el programa en algo que puede ser evaluado de manera más eficiente haciendo todo el trabajo posible de antemano. Por ejemplo, en lenguajes bien diseñados es obvio, para cada uso de una ((variable)), a qué variable se refiere, sin ejecutar realmente el programa. Esto puede usarse para evitar buscar la variable por nombre cada vez que se accede y para buscarla directamente desde una ubicación de ((memoria)) predeterminada. -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. +Traditionally, ((compilation))Tradicionalmente, la compilación implica convertir el programa en ((código de máquina)), el formato en bruto que el procesador de una computadora puede ejecutar. Pero cualquier proceso que convierte un programa en una representación diferente puede considerarse como compilación. -(((simplicity)))(((Function constructor)))(((transpilation)))It would -be possible to write an alternative ((evaluation)) strategy for Egg, -one that first converts the program to a JavaScript program, uses `new -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. +(((simplicity)))(((Function constructor)))(((transpilation)))Sería posible escribir una estrategia de ((evaluación)) alternativa para "Egg", una que primero convierta el programa a un programa JavaScript, utilice una nueva Función para invocar al compilador de JavaScript y luego ejecute el resultado. Cuando se haga bien, esto hará que "Egg" corra muy rápido sin dejar de ser muy sencillo de implementar. -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. +Si está interesado en este tema y está dispuesto a dedicar algo de tiempo a ello, le animo a que intente implementar un compilador como un ejercicio. -== Cheating == +== Trampeando == -(((Egg language)))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. +(((Egg language)))Cuando definimos `if` y `while`, probablemente notó que eran envolturas más o menos triviales alrededor de los propios `if` y `while` de JavaScript. Del mismo modo, los valores de "Egg" son sólo antiguos valores de JavaScript. -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. +Si comparas la implementación de Egg, construida por encima de JavaScript, con la cantidad de trabajo y complejidad requerida para construir un lenguaje de programación directamente en la funcionalidad bruta proporcionada por una máquina, la diferencia es enorme. Independientemente, este ejemplo esperamos le dio una impresión de la forma en que funcionan los ((lenguajes de programación)). -And when it comes to getting something done, cheating is more -effective than doing everything yourself. Though the toy language in -this chapter doesn't do anything that couldn't be done better in -JavaScript, there _are_ situations where writing small languages helps -get real work done. +Y cuando se trata de hacer algo, hacer trampa es más eficaz que hacer todo tú mismo. Aunque el lenguaje de juguete de este capítulo no hace nada que no se pueda hacer mejor en JavaScript, hay situaciones en las que escribir lenguajes pequeños ayuda a realizar un trabajo real. -Such a language does not have to resemble a typical programming -language. If JavaScript didn't come equipped with regular expressions, -you could write your own parser and evaluator for such a sublanguage. +Tal lenguaje no tiene que parecerse a un lenguaje de programación típico. Si JavaScript no viene equipado con expresiones regulares, puede escribir su propio analizador y evaluador para tal sublenguaje. -(((artificial intelligence)))Or imagine you are building a giant -robotic ((dinosaur)) and need to program its ((behavior)). JavaScript -might not be the most effective way to do this. You might instead opt -for a language that looks like this: +(((artificial intelligence)))O imagínese que está construyendo un gigantesco ((dinosaurio)) robótico y necesita programar su ((comportamiento)). JavaScript podría no ser la forma más efectiva de hacerlo. En su lugar, puede optar por un idioma que tenga el siguiente aspecto: ---- behavior walk @@ -667,21 +475,13 @@ behavior attack launch arm-rockets ---- -(((expressivity)))This is what is usually called a _((domain-specific -language))_, a language tailored to express a narrow domain of -knowledge. Such a language can be more expressive than a -general-purpose language because it is designed to express exactly the -things that need expressing in its domain and nothing else. +(((expressivity)))Esto es lo que se suele llamar un _((lenguaje específico del dominio))_, un lenguaje adaptado para expresar un estrecho dominio del conocimiento. Tal lenguaje puede ser más expresivo que un lenguaje de propósito general porque está diseñado para expresar exactamente las cosas que necesitan expresarse en su dominio y nada más. -== Exercises == +== Ejercicios == === Arrays === -(((Egg language)))Add support for ((array))s to Egg by adding the -following three functions to the top scope: `array(...)` to -construct an array containing the argument values, `length(array)` to -get an array's length, and `element(array, n)` to fetch the n^th^ -element from an array. +(((Egg language)))Agregue soporte para arrays a "Egg" agregando las siguientes tres funciones al ámbito superior: `array (...)` para construir una matriz que contenga el valor de sus argumentos, `length(array)` para obtener la longitud de una matriz y `element(array, n)` para buscar la posición del elemento en el array. ifdef::interactive_target[] @@ -711,25 +511,17 @@ endif::interactive_target[] !!hint!! -The easiest way to do this is to represent Egg arrays -with JavaScript arrays. +La forma más sencilla de hacerlo es representar arrays de "Egg" con arrays de JavaScript. -(((slice method)))The values added to the top environment must be -functions. `Array.prototype.slice` can be used to convert an -`arguments` array-like object into a regular array. +(((slice method)))Los valores agregados al entorno superior deben ser funciones. `Array.prototype.slice` se puede utilizar para convertir `arguments` en un objecto array. !!hint!! === Closure === -(((closure)))(((function,scope)))The way we have defined `fun` allows -functions in Egg to “close over” the surrounding environment, allowing -the function's body to use local values that were visible at the time -the function was defined, just like JavaScript functions do. +(((closure)))(((function,scope)))La forma en que hemos definido `fun` permite a las funciones de "Egg" "cerrar" el entorno, permitiendo que el cuerpo de la función use valores locales que eran visibles en el momento en que se definió la función, al igual que las funciones de JavaScript. -The following program illustrates this: function `f` returns a function -that adds its argument to `f`'s argument, meaning that it needs access -to the local ((scope)) inside `f` to be able to use variable `a`. +El siguiente programa lo ilustra: la función `f` devuelve una función que añade su argumento como argumentos de `f`, lo que significa que necesita acceso al ámbito local dentro de `f` para poder utilizar la variable `a`. [source,javascript] ---- @@ -738,39 +530,21 @@ run("do(define(f, fun(a, fun(b, +(a, b)))),", // → 9 ---- -Go back to the definition of the `fun` form and explain which -mechanism causes this to work. +Vuelva a la definición de `fun` y explique qué mecanismo hace que funcione. !!hint!! -(((closure)))Again, we are riding along on a JavaScript mechanism to -get the equivalent feature in Egg. Special forms are passed the local -environment in which they are evaluated so that they can evaluate -their subforms in that environment. The function returned by `fun` -closes over the `env` argument given to its enclosing function and -uses that to create the function's local ((environment)) when it is -called. - -(((compilation)))This means that the ((prototype)) of the local -environment will be the environment in which the function was created, -which makes it possible to access variables in that environment from -the function. This is all there is to implementing closure (though to -compile it in a way that is actually efficient, you'd need to do some -more work). +(((closure)))Una vez más, estamos montando sobre un mecanismo JavaScript para obtener la característica equivalente en "Egg". Se pasan funciones especiales al entorno local en el que se evalúan para que puedan evaluar subfunciones dentro de ese entorno. La función devuelta por `fun` actua sobre el argumento `env` que se da a su función enclosing y usa eso, para crear el entorno local de la función cuando es llamada. + +(((compilation)))Esto significa que el ((prototype)) del entorno local será el entorno en el que se creó la función, lo que hace posible acceder a las variables en ese entorno desde la función. Esto es todo lo que hay que hacer para implementar el Closure (aunque para compilarlo de una manera que es realmente eficiente, tendría que hacer un poco más de trabajo). !!hint!! -=== Comments === +=== Comentarios === -(((hash character)))(((Egg language)))It would be nice if we could -write ((comment))s in Egg. For example, whenever we find a hash sign -(`#`), we could treat the rest of the line as a comment and ignore it, -similar to `//` in JavaScript. +(((hash character)))(((Egg language)))Sería bueno si pudiéramos escribir ((comentarios)) en "Egg". Si nosotros encontramos el hash (`#`), podríamos tratar el resto de la línea como un comentario e ignorarlo, similar a `//` en JavaScript. -(((skipSpace function)))We do not have to make any big changes to the -parser to support this. We can simply change `skipSpace` to skip -comments like they are ((whitespace)) so that all the points where -`skipSpace` is called will now also skip comments. Make this change. +(((skipSpace function)))No tenemos que hacer grandes cambios en el analizador para apoyar esto. Podemos simplemente cambiar `skipSpace` para omitir los comentarios como si fueran ((espacios en blanco)) para que todos los puntos donde `skipSpace` se llama ahora también saltarán los comentarios. Haga este cambio. ifdef::interactive_target[] @@ -797,42 +571,22 @@ endif::interactive_target[] !!hint!! -(((comment)))Make sure your solution handles multiple comments in a -row, with potentially ((whitespace)) between or after them. +(((comment)))Asegúrese de que su solución maneja varios comentarios en una fila, pudiendo ((aparecer espacios en blanco)) entre o después de ellos. -A ((regular expression)) is probably the easiest way to solve this. -Write something that matches “whitespace or a comment, zero or more -times”. Use the `exec` or `match` method and look at the length of -the first element in the returned array (the whole match) to find out -how many characters to slice off. +A ((regular expression))Una expresión regular es probablemente la manera más fácil de resolver esto. Escriba algo que coincida con "espacios en blanco o un comentario, cero o más veces". Utilice el método `exec` o `match` y observe la longitud del primer elemento del Array devuelto (la coincidencia completa) para averiguar cuántos caracteres quitar. !!hint!! -=== Fixing scope === +=== Fijando el alcance === -(((variable,definition)))(((assignment)))Currently, the only way to -assign a ((variable)) a value is `define`. This construct acts as -a way both to define new variables and to give existing ones a new value. +(((variable,definition)))(((assignment)))Actualmente, la única forma de asignar una ((variable)) a un valor es `define`. Esta construcción actúa para definir nuevas variables como para dar a las existentes un nuevo valor. -(((local variable)))This ((ambiguity)) causes a problem. When you try -to give a nonlocal variable a new value, you will end up defining a -local one with the same name instead. (Some languages work like this -by design, but I've always found it a silly way to handle ((scope)).) +(((local variable)))This ((ambiguity))Esta ambigüedad causa un problema. Cuando intenta dar una variable no local un nuevo valor, terminará definiendo una en local con el mismo nombre en su lugar. (Algunos lenguajes funcionan de esta manera por diseño, pero siempre he encontrado una manera simple de manejar el ((alcance)).) -(((ReferenceError type)))Add a special form `set`, similar to -`define`, which gives a variable a new value, updating the variable in -an outer scope if it doesn't already exist in the inner scope. If the -variable is not defined at all, throw a `ReferenceError` (which is -another standard error type). +(((ReferenceError type)))Agregue una functión especial `set`, similar a `define`, la cual da a una variable un nuevo valor, actualizando la variable en un ámbito externo si aún no existe en el ámbito interno. Si la variable no está definida en absoluto, lance un `ReferenceError` (El cual es otro tipo de error estándar). (((hasOwnProperty method)))(((prototype)))(((getPrototypeOf -function)))The technique of representing scopes as simple objects, -which has made things convenient so far, will get in your way a -little at this point. You might want to use the -`Object.getPrototypeOf` function, which returns the prototype of an -object. Also remember that scopes do not derive from -`Object.prototype`, so if you want to call `hasOwnProperty` on them, -you have to use this clumsy expression: +function)))La técnica de representar los ámbitos como objetos simples, ha hecho las cosas convenientes hasta ahora, se pondrá en contra un poco en este punto. Es posible que desee utilizar la función `Object.getPrototypeOf`, que devuelve el prototipo de un objeto. También recuerde que los ámbitos no derivan de `Object.prototype`, así que si quieres llamar a `hasOwnProperty` en ellos, debes usar esta expresión: // test: no @@ -841,8 +595,7 @@ you have to use this clumsy expression: Object.prototype.hasOwnProperty.call(scope, name); ---- -This fetches the `hasOwnProperty` method from the `Object` prototype -and then calls it on a scope object. +Esto recupera el método `hasOwnProperty` del prototipo de `Object` y lo llama a un objeto scope. ifdef::interactive_target[] @@ -867,15 +620,8 @@ endif::interactive_target[] !!hint!! (((variable,definition)))(((assignment)))(((getPrototypeOf -function)))(((hasOwnProperty method)))You will have to loop through -one ((scope)) at a time, using `Object.getPrototypeOf` to go the next -outer scope. For each scope, use `hasOwnProperty` to find out whether the -variable, indicated by the `name` property of the first argument to -`set`, exists in that scope. If it does, set it to the result of -evaluating the second argument to `set` and then return that value. - -(((global scope)))(((run-time error)))If the outermost scope is -reached (`Object.getPrototypeOf` returns null) and we haven't found -the variable yet, it doesn't exist, and an error should be thrown. +function)))(((hasOwnProperty method)))Tendrá que realizar un bucle sobre un ((scope)) a la vez, utilizando `Object.getPrototypeOf` para ir al siguiente ((scope)) externo. Para cada ((scope)), use `hasOwnProperty` para averiguar si la variable, indicada por la propiedad `name` del primer argumento de `set`, Si lo hace, póngalo en el resultado de evaluar el segundo argumento a `set` y luego devolver ese valor. + +(((global scope)))(((run-time error)))Si alcanzamos el ámbito más alejado (`Object.getPrototypeOf` devuelve null) y no hemos encontrado la variable todavía, no existe, y se debe lanzar un error. !!hint!! diff --git a/12_browser.txt b/12_browser.txt index b870befd8..2bf182345 100644 --- a/12_browser.txt +++ b/12_browser.txt @@ -109,8 +109,8 @@ the ((Internet)), and have it listen on port 80, using the _Hypertext Transfer Protocol_ (HTTP). This protocol allows other computers to request documents over the ((network)). -indexsee:[Universal Resource Locator,URL] -(((URL)))Each ((document)) on the Web is named by a _Universal Resource +indexsee:[Uniform Resource Locator,URL] +(((URL)))Each ((document)) on the Web is named by a _Uniform Resource Locator_ (URL), which looks something like this: ---- diff --git a/17_http.txt b/17_http.txt index 1e86dc816..b6e9207c1 100644 --- a/17_http.txt +++ b/17_http.txt @@ -294,7 +294,7 @@ URL. (((send method)))(((GET method)))(((body (HTTP))))(((responseText property)))After opening the request, we can send it with the `send` method. The argument to send is the request body. For `GET` requests, -we can pass null. If the third argument to `open` was `false`, `send` +we can pass `null`. If the third argument to `open` was `false`, `send` will return only after the response to our request was received. We can read the request object's `responseText` property to get the response body. @@ -338,7 +338,7 @@ does not know how to handle. I/O)))(((responseText property)))(((send method)))In the examples we saw, the request has finished when the call to `send` returns. This is convenient because it means properties such as `responseText` are -available immediately. But it also mean that our program is suspended +available immediately. But it also means that our program is suspended as long as the ((browser)) and server are communicating. When the ((connection)) is bad, the server is slow, or the file is big, that might take quite a while. Worse, because no event handlers can fire @@ -386,7 +386,7 @@ the ((DOM)) discussed in link:13_dom.html#dom[Chapter 13], except that it doesn't have HTML-specific functionality like the `style` property. The object that `responseXML` holds corresponds to the `document` object. Its `documentElement` property refers to the outer tag of the -XML document. In the following document (_example/fruit.xml_), that would +XML document. In the following document (_example/fruit.xml_), that would be the `` tag: [source,application/xml] diff --git a/18_forms.txt b/18_forms.txt index c717c5040..283190ed6 100644 --- a/18_forms.txt +++ b/18_forms.txt @@ -64,7 +64,7 @@ JavaScript, we often do not want to submit our fields normally anyway.

(radio)

-

(file)

+

(file)

---- ifdef::book_target[] diff --git a/Makefile b/Makefile index 6955ed54e..2d8430400 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ CHAPTERS := 00_intro 01_values 02_program_structure 03_functions 04_data 05_high SVGS := $(wildcard img/*.svg) -html: $(foreach CHAP,$(CHAPTERS),html/$(CHAP).html) html/js/chapter_info.js html/js/acorn_codemirror.js \ - code/skillsharing.zip code/solutions/20_4_a_public_space_on_the_web.zip \ +html: $(foreach CHAP,$(CHAPTERS),html/$(CHAP).html) html/js/acorn_codemirror.js \ + code/skillsharing.zip code/solutions/20_4_a_public_space_on_the_web.zip html/js/chapter_info.js \ $(patsubst img/%.svg,img/generated/%.png,$(SVGS)) html/%.html: %.txt asciidoc_html.conf diff --git a/bin/chapter_info.js b/bin/chapter_info.js index d6662bf08..4a0a1e495 100644 --- a/bin/chapter_info.js +++ b/bin/chapter_info.js @@ -95,7 +95,7 @@ dir.forEach(function(file) { solution: fs.readFileSync("code/solutions/20_3_creating_directories.js", "utf8") }, {name: "A public space on the web", - file: "code/solutions/20_4_a_public_space_on_the_web", + file: "code/solutions/20_4_a_public_space_on_the_web.zip", number: 4, type: "js", code: nodeInfo, diff --git a/code/solutions/02_1_looping_a_triangle.js b/code/solutions/02_1_iterando_un_tringulo.js similarity index 100% rename from code/solutions/02_1_looping_a_triangle.js rename to code/solutions/02_1_iterando_un_tringulo.js diff --git a/code/solutions/02_3_chess_board.js b/code/solutions/02_3_tablero_de_ajedrez.js similarity index 100% rename from code/solutions/02_3_chess_board.js rename to code/solutions/02_3_tablero_de_ajedrez.js diff --git a/code/solutions/04_1_the_sum_of_a_range.js b/code/solutions/04_1_the_sum_of_a_range.js index b62b5308e..ff480e46e 100644 --- a/code/solutions/04_1_the_sum_of_a_range.js +++ b/code/solutions/04_1_the_sum_of_a_range.js @@ -19,7 +19,9 @@ function sum(array) { return total; } -console.log(sum(range(1, 10))); -// → 55 +console.log(range(1, 10)) +// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(range(5, 2, -1)); // → [5, 4, 3, 2] +console.log(sum(range(1, 10))); +// → 55 diff --git a/code/solutions/07_1_artificial_stupidity.js b/code/solutions/07_1_artificial_stupidity.js index 832eae143..cac0da98e 100644 --- a/code/solutions/07_1_artificial_stupidity.js +++ b/code/solutions/07_1_artificial_stupidity.js @@ -2,14 +2,14 @@ function SmartPlantEater() { this.energy = 30; this.direction = "e"; } -SmartPlantEater.prototype.act = function(context) { - var space = context.find(" "); +SmartPlantEater.prototype.act = function(view) { + var space = view.find(" "); if (this.energy > 90 && space) return {type: "reproduce", direction: space}; - var plants = context.findAll("*"); + var plants = view.findAll("*"); if (plants.length > 1) return {type: "eat", direction: randomElement(plants)}; - if (context.look(this.direction) != " " && space) + if (view.look(this.direction) != " " && space) this.direction = space; return {type: "move", direction: this.direction}; }; diff --git a/code/solutions/07_2_predators.js b/code/solutions/07_2_predators.js index 01be29fc2..c19a43dbc 100644 --- a/code/solutions/07_2_predators.js +++ b/code/solutions/07_2_predators.js @@ -2,14 +2,14 @@ function SmartPlantEater() { this.energy = 30; this.direction = "e"; } -SmartPlantEater.prototype.act = function(context) { - var space = context.find(" "); +SmartPlantEater.prototype.act = function(view) { + var space = view.find(" "); if (this.energy > 90 && space) return {type: "reproduce", direction: space}; - var plants = context.findAll("*"); + var plants = view.findAll("*"); if (plants.length > 1) return {type: "eat", direction: randomElement(plants)}; - if (context.look(this.direction) != " " && space) + if (view.look(this.direction) != " " && space) this.direction = space; return {type: "move", direction: this.direction}; }; @@ -20,12 +20,12 @@ function Tiger() { // Used to track the amount of prey seen per turn in the last six turns this.preySeen = []; } -Tiger.prototype.act = function(context) { +Tiger.prototype.act = function(view) { // Average number of prey seen per turn var seenPerTurn = this.preySeen.reduce(function(a, b) { return a + b; }, 0) / this.preySeen.length; - var prey = context.findAll("O"); + var prey = view.findAll("O"); this.preySeen.push(prey.length); // Drop the first element from the array when it is longer than 6 if (this.preySeen.length > 6) @@ -35,10 +35,10 @@ Tiger.prototype.act = function(context) { if (prey.length && seenPerTurn > 0.25) return {type: "eat", direction: randomElement(prey)}; - var space = context.find(" "); + var space = view.find(" "); if (this.energy > 400 && space) return {type: "reproduce", direction: space}; - if (context.look(this.direction) != " " && space) + if (view.look(this.direction) != " " && space) this.direction = space; return {type: "move", direction: this.direction}; }; diff --git a/code/solutions/09_1_regexp_golf.js b/code/solutions/09_1_regexp_golf.js index 00582a537..6848f0f18 100644 --- a/code/solutions/09_1_regexp_golf.js +++ b/code/solutions/09_1_regexp_golf.js @@ -16,7 +16,7 @@ verify(/ious\b/, ["how delicious", "spacious room"], ["ruinous", "consciousness"]); -verify(/\s[.,;]/, +verify(/\s[.,:;]/, ["bad punctuation ."], ["escape the dot"]); diff --git a/code/solutions/20_1_content_negotiation_again.js b/code/solutions/20_1_content_negotiation_again.js index 6c145c028..de4e0ae06 100644 --- a/code/solutions/20_1_content_negotiation_again.js +++ b/code/solutions/20_1_content_negotiation_again.js @@ -19,6 +19,10 @@ function readStreamAsString(stream, callback) { path: "/author", headers: {Accept: type} }, function(response) { + if (response.statusCode != 200) { + console.error("Request for " + type + " failed: " + response.statusMessage); + return; + } readStreamAsString(response, function(error, content) { if (error) throw error; console.log("Type " + type + ": " + content); diff --git a/code/solutions/20_2_fixing_a_leak.js b/code/solutions/20_2_fixing_a_leak.js index 86b04cf0b..e66f85089 100644 --- a/code/solutions/20_2_fixing_a_leak.js +++ b/code/solutions/20_2_fixing_a_leak.js @@ -2,7 +2,7 @@ // code/file_server_promises.js already contain this fixed version. function urlToPath(url) { - var path = url; + var path = require("url").parse(url).pathname; var decoded = decodeURIComponent(path); return "." + decoded.replace(/(\/|\\)\.\.(\/|\\|$)/g, "/"); } diff --git a/html/css/ejs.css b/html/css/ejs.css index 228122438..5c536e5b9 100644 --- a/html/css/ejs.css +++ b/html/css/ejs.css @@ -61,8 +61,9 @@ pre[data-language=javascript] { p:hover a.p_ident:after, pre:hover a.c_ident:after, h2:hover a.h_ident:after, h3:hover a.h_ident:after { content: "¶"; + font-family: 'Cinzel', Georgia, serif; color: #888; - font-size: 80%; + font-size: 17px; position: absolute; right: -25px; } diff --git a/html/errata.html b/html/errata.html index a8b475250..df884c739 100644 --- a/html/errata.html +++ b/html/errata.html @@ -20,7 +20,7 @@

Errata
El

Issues whose section title is followed by a superscript ¹ were fixed after the first print of the book, and will not be present in -later prints.

+later prints. Those followed by ² were fixed in the third print.

Introduction

@@ -28,15 +28,28 @@

Introduction

can probably imagine how how tedious…” duplicates the word how.

+

Chapter 2

+ +

Page 32 (while and do Loops²): The var +name example unintentionally exits the loop when the dialog is +canceled, because browsers have a built-in global +variable name whose values are implicitly converted to +strings.

+

Chapter 9

+

Page 157 (Repeating Parts of a Pattern): The +paragraph at the top of the page claims that {,5} is equivalent to +{0,5} in a regular expression. This is not the case (you +have to include the zero).

+

Page 159 (The Date Type¹): The findDate function produces the wrong months. The second argument given to new Date should be Number(match[2]) - 1, subtracting one to compensate for the fact that months start at zero in this interface.

-

Page 162 (Backtracking): The regular expression +

Page 162 (Backtracking²): The regular expression should have another + sign after the [\da-f] group to match what it is described as matching. The diagram for the expression is similarly missing an arrow looping back around the @@ -55,6 +68,12 @@

Chapter 11

its parentheses distributed incorrectly. One closing parentheses from the second line should be moved to the end of the last line.

+

Chapter 12

+ +

Page 209 (The Web²): In the third paragraph I claim +that the U in “URL” stands for Universal, whereas it actually +stands for Uniform.

+

Chapter 14

Page 242 (Mouse Motion¹): The example @@ -82,6 +101,10 @@

Chapter 17

Chapter 18

+

Page 316 (Fields²): The checked +attribute in the file field at the bottom of the example +doesn't mean anything, and should not be there.

+

Page 327 (Summary¹): “When the user has selected a field” should be “When the user has selected a file”. diff --git a/html/index.html b/html/index.html index 8a96ba635..36a482de5 100644 --- a/html/index.html +++ b/html/index.html @@ -13,7 +13,7 @@

Eloquent JavaScript
second edition

paperback copy of the book.

- Cover image + Cover image

Written by Marijn Haverbeke.

@@ -101,4 +101,12 @@

Other pages

  • The first edition of the book
  • +

    Translations

    + + + diff --git a/html/js/code.js b/html/js/code.js index 90d93068d..8dbf97f34 100644 --- a/html/js/code.js +++ b/html/js/code.js @@ -140,7 +140,11 @@ addEventListener("load", function() { type: exercise.type}; setEditorCode(exercise.code, exercise.type); visible = "exercise"; - document.querySelector("#download").href = "data:text/plain;charset=UTF-8," + exercise.solution; + var link = document.querySelector("#download"); + if (/\.zip$/.test(exercise.file)) + link.href = exercise.file + else + link.href = "data:text/plain;charset=UTF-8," + exercise.solution; } ["box", "exercise"].forEach(function(id) { document.querySelector("#" + id + "_info").style.display = diff --git a/mkcopy b/mkcopy new file mode 100755 index 000000000..ce8b465f2 --- /dev/null +++ b/mkcopy @@ -0,0 +1,2 @@ +make html +yes | cp -rf html/* ../Eloquent-Javscritp-es-online/chapters \ No newline at end of file