forked from hectorip/Eloquent-JavaScript-es
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path02_program_structure.txt
More file actions
1034 lines (835 loc) · 39.9 KB
/
02_program_structure.txt
File metadata and controls
1034 lines (835 loc) · 39.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
:chap_num: 2
:prev_link: 01_values
:next_link: 03_functions
= Estructura del Programa =
[chapterquote="true"]
[quote, _why, Why's (Poignant) Guide to Ruby]
____
Y mi corazón brilla rojo debajo de mi
delgada, translúcida piel y tienen que administrarme 10cc de JavaScript
para hacerme regresar (respondo bien a las toxinas en la sangre). ¡Hombre,
esa cosa te sacará de tus casillas!
____
(((why)))(((Poignant Guide)))En este capítulo, vamos a empezar a hacer
cosas que realmente pueden ser llamadas _programación_. Vamos a ampliar
nuestro conocimiento del lenguaje JavaScript, más allá de los sustantivos
y fragmentos de oraciones que hemos visto hasta ahora,
hasta el punto en que podamos expresar alguna prosa significativa.
== Expresiones y declaraciones ==
(((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. Crear valores de esta forma
es una parte esencial de cada programa de JavaScript, pero esto es sólo
una parte.
(((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 un ((operador
binario)) aplicado a dos expresiones o un operador unario aplicado a
una expresion.
(((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.
(((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. Esto es un programa:
[source,javascript]
----
1;
!false;
----
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
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 ==
(((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 atrapado = 5 * 5;
----
(((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 `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
variable alberga actualmente. He aquí un ejemplo:
[source,javascript]
----
var diez = 10;
console.log(diez * diez);
// → 100
----
(((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 `_`.
(((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 tono = "claro";
console.log(tono);
// → claro
tono = "oscuro";
console.log(tono);
// → oscuro
----
(((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 te paga $35,
le das a esta variable un valor nuevo.
[source,javascript]
----
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 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 declaración `var` puede definir múltiples
variables. Las definiciones deben estar separadas por comas.
[source,javascript]
----
var uno = 1, dos = 2;
console.log(uno + dos);
// → 3
----
== Palabras clave y palabras reservadas ==
(((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
“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]
----
break case catch class const continue debugger
default delete do else enum export extends false
finally for function if implements import in
instanceof interface let new null package private
protected public return static super switch this
throw true try typeof var void while with yield
----
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 un
programa se pone en marcha, este entorno no está vacío. Siempre contiene
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 entrada del ((ratón)) y del ((teclado)).
== Funciones ==
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("¡Good Morning!");
----
image::img/alert.png[alt="An alert dialog",width="8cm"]
(((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 función `alert`
necesita solo uno, pero otras funciones pueden necesitar un
número diferente o diferentes tipos de argumentos.
== 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[]
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("el valor de x es", x);
// → el valor de x es 30
----
(((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]]
== Valores de Retorno ==
(((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]
----
console.log(Math.max(2, 4));
// → 4
----
(((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]
----
console.log(Math.min(2, 4) + 100);
// → 102
----
El link:03_functions.html#functions[próximo capítulo] explica como escribir
tus propias funciones.
== Pedir información y confirmar ==
(((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("¿Entonces, deberíamos?");
----
image::img/confirm.png[alt="A confirm dialog",width="8cm"]
(((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]
----
prompt("Tell me everything you know.", "...");
----
image::img/prompt.png[alt="An prompt dialog",width="8cm"]
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 de flujo ==
(((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 elNumero = Number(prompt("Dame un número", ""));
alert("Tú número es la raíz cuadrada de " +
elNumero * elNumero);
----
(((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.
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"]
== Ejecución Condicional ==
(((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"]
(((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 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.
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.
(((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”.
(((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 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. ¿Por qué no me diste un número?");
----
(((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("Dame un número", "0"));
if (num < 10)
alert("Chico");
else if (num < 100)
alert("Mediano");
else
alert("Grande");
----
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.
El diagrama de flujo para este programa es algo así:
image::img/controlflow-nested-if.svg[alt="Nested if control flow",width="4cm"]
[[bucles]]
== bucles while y do ==
(((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]
----
console.log(0);
console.log(2);
console.log(4);
console.log(6);
console.log(8);
console.log(10);
console.log(12);
----
(((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"]
(((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 numero = 0;
while (numero <= 12) {
console.log(numero);
numero = numero + 2;
}
// → 0
// → 2
// … etcetera
----
(((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 resultado = 1;
var contador = 0;
while (contador < 10) {
resultado = resultado * 2;
contador = contador + 1;
}
console.log(resultado);
// → 1024
----
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.
(((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 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 numero = 0; numero <= 12; numero = numero + 2)
console.log(numero);
// → 0
// → 2
// … etc.
----
(((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.
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`.
(((exponenciación)))Aquí está un código que calcula 2^10^, usando el `for`
en vez del `while`.
[source,javascript]
----
var resultado = 1;
for (var contador = 0; contador < 10; contador = contador + 1)
resultado = resultado * 2;
console.log(resultado);
// → 1024
----
(((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.
== Forzando la salida de un bucle ==
(((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.
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 actual = 20; ; actual++) {
if (actual % 7 == 0)
break;
}
console.log(actual);
// → 21
----
(((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.
(((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.
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[]
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[]
(((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.
== Actualizando variables sucintamente ==
(((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]
----
contador = contador + 1;
----
JavaScript nos da un atajo para esto:
// test: no
[source,javascript]
----
contador += 1;
----
Atajos similares funcionan igual para muchos otros operadores, como
`resultado *= 2` para duplicar `resultado` o `counter -= 1` para restar uno.
Esto nos permite acortar nuestro ejemplo de la cuenta un poco más.
[source,javascript]
----
for (var numero = 0; numero <= 12; numero += 2)
console.log(numero);
----
(((operador ++)))(((operador --)))Para `contador += 1` y `contador -= 1`,
hay incluso equivalentes más cortos: `contador+=` y `contador--`.
== Despachando sobre un valor con switch ==
(((sintaxis)))(((ejecución condicional)))(((despachando)))(((palabra clave if,
encadenamiento)))Es común ver código así:
// test: no
[source,javascript]
----
if (variable == "valor1") accion1();
else if (variable == "valor2") accion2();
else if (variable == "valor3") accion3();
else accionDefault();
----
(((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("¿Cómo está el clima?")) {
case "lluvioso":
console.log("Recuerda llevar un paraguas.");
break;
case "soleado":
console.log("Viste ligero.");
case "nublado":
console.log("Sal a la calle.");
break;
default:
console.log("Tipo de Clima desconocido.");
break;
}
----
(((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 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.
----
(((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]
----
/*
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 miNumero = 11213;
----
== Sumario ==
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.
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`).
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.
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.
== Ejercicios ==
(((ejercicios)))Si no estás seguro de cómo probar tus soluciones a los
ejercicios, visita la link:00_intro.html#intro[introducción]
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_].
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.
=== Iterando un triángulo ===
(((triángulo (ejercicio))))Escribe un ((bucle)) que haga siete
llamadas a `console.log` para producir el siguiente triángulo:
----
#
##
###
####
#####
######
#######
----
Puede ser útil saber que puedes encontrar la longitud de una cadena
de texto escribiendo `.length` después de ella.
[source,javascript]
----
var abc = "abc";
console.log(abc.length);
// → 3
----
ifdef::interactive_target[]
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]
----
// Tu código aquí:
----
endif::interactive_target[]
!!hint!!
(((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`.
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 (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"`.
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).
(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]
----
// Tu código aquí:
----
endif::interactive_target[]
!!hint!!
(((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).
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`.
(((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!!
=== Tablero de Ajedrez ===
(((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.
Pasar esta cadena a `console.log` debería mostrar algo como esto:
----
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
----
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[]