034.3 Lección 1
Certificación: |
Conceptos básicos de desarrollo web |
---|---|
Versión: |
1.0 |
Tema: |
034 Programación JavaScript |
Objetivo: |
034.3 Funciones y estructuras de control de JavaScript |
Lección: |
1 de 2 |
Introducción
Como cualquier otro lenguaje de programación, el código JavaScript es una colección de declaraciones que le indica al intérprete de instrucciones qué hacer en orden secuencial. Sin embargo, esto no significa que cada instrucción deba ejecutarse solo una vez o que deban ejecutarse en absoluto. La mayoría de las declaraciones deben ejecutarse solo cuando se cumplen condiciones específicas. Incluso cuando una secuencia de comandos se activa de forma asincrónica por eventos independientes, a menudo tiene que comprobar una serie de variables de control para averiguar la parte correcta del código a ejecutar.
Estructuras If
La estructura de control más simple viene dada por la instrucción if
, que ejecutará la instrucción inmediatamente después si la condición especificada es verdadera. JavaScript considera que las condiciones son verdaderas si el valor evaluado es distinto de cero. Todo lo que esté entre paréntesis después de la palabra if
(los espacios se ignoran) se interpretará como una condición. En el siguiente ejemplo, el número literal 1
es la condición:
if ( 1 ) console.log("1 is always true");
El número 1
está escrito explícitamente en esta condición de ejemplo, por lo que se trata como un valor constante (permanece igual durante la ejecución del script) y siempre dará como resultado verdadero cuando se use como expresión condicional. La palabra true
también podría usarse en lugar de 1
, ya que el lenguaje también la trata como un valor verdadero literal. La instrucción console.log
imprime sus argumentos en la ventana de la consola del navegador.
Tip
|
La consola del navegador muestra errores, advertencias y mensajes informativos enviados con la instrucción de JavaScript |
Aunque sintácticamente correcto, el uso de expresiones constantes en condiciones no es muy útil. En una aplicación real, probablemente querrá probar la veracidad de una variable:
let my_number = 3;
if ( my_number ) console.log("The value of my_number is", my_number, "and it yields true");
El valor asignado a la variable my_number
(3
) es distinto de cero, por lo que arroja verdadero. Pero este ejemplo no es de uso común, porque rara vez es necesario probar si un número es igual a cero. Es mucho más común comparar un valor con otro y probar si el resultado es verdadero:
let my_number = 3;
if ( my_number == 3 ) console.log("The value of my_number is", my_number, "indeed");
El operador de comparación doble igual se utiliza porque el operador igual simple ya está definido como operador de asignación. El valor a cada lado del operador se llama operand. El orden de los operandos no importa y cualquier expresión que devuelva un valor puede ser un operando. Aquí una lista de otros operadores de comparación disponibles:
value1 == value2
-
True if
value1
is equal tovalue2
. value1 != value2
-
True if
value1
is not equal tovalue2
. value1 < value2
-
True if
value1
is less thanvalue2
. value1 > value2
-
True if
value1
is greater thanvalue2
. value1 <= value2
-
True if
value1
is less than or equal tovalue2
. value1 >= value2
-
True if
value1
is grater than or equal tovalue2
.
Por lo general, no importa si el operando a la izquierda del operador es una cadena de texto y el operando a la derecha es un número, siempre que JavaScript pueda convertir la expresión en una comparación significativa. Por lo tanto, la cadena que contiene el caracter 1
se tratará como el número 1 en comparación con una variable numérica. Para asegurarse de que la expresión sea verdadera solo si ambos operandos son exactamente del mismo tipo y valor, se debe usar el operador de identidad estricto ===
en lugar de ==
. Del mismo modo, el operador estricto sin identidad !==
se evalúa como verdadero si el primer operando no es exactamente del mismo tipo y valor que el segundo operador.
Opcionalmente, la estructura de control if
puede ejecutar una declaración alternativa cuando la expresión se evalúa como falsa:
let my_number = 4;
if ( my_number == 3 ) console.log("The value of my_number is 3");
else console.log("The value of my_number is not 3");
La instrucción else
debe seguir inmediatamente a la instrucción if
. Hasta ahora, estamos ejecutando solo una declaración cuando se cumple la condición. Para ejecutar más de una instrucción, debe encerrarlas entre llaves:
let my_number = 4;
if ( my_number == 3 )
{
console.log("The value of my_number is 3");
console.log("and this is the second statement in the block");
}
else
{
console.log("The value of my_number is not 3");
console.log("and this is the second statement in the block");
}
Un grupo de una o más declaraciones delimitadas por un par de llaves se conoce como declaración de bloque. Es común usar sentencias de bloque incluso cuando solo hay una instrucción para ejecutar, para que el estilo de codificación sea consistente en todo el script. Además, JavaScript no requiere que las llaves o cualquier declaración estén en líneas separadas, pero hacerlo mejora la legibilidad y facilita el mantenimiento del código.
Las estructuras de control se pueden anidar unas dentro de otras, pero es importante no mezclar las llaves de apertura y cierre de cada declaración de bloque:
let my_number = 4;
if ( my_number > 0 )
{
console.log("The value of my_number is positive");
if ( my_number % 2 == 0 )
{
console.log("and it is an even number");
}
else
{
console.log("and it is an odd number");
}
} // end of if ( my_number > 0 )
else
{
console.log("The value of my_number is less than or equal to 0");
console.log("and I decided to ignore it");
}
Las expresiones evaluadas por la instrucción if
pueden ser más elaboradas que las comparaciones simples. Este es el caso en el ejemplo anterior, donde se empleó la expresión aritmética my_number % 2
entre paréntesis en el if
anidado. El operador %
devuelve el resto después de dividir el número de su izquierda por el número de su derecha. Los operadores aritméticos como %
tienen prioridad sobre los operadores de comparación como ==
, por lo que la comparación utilizará el resultado de la expresión aritmética como su operando izquierdo.
En muchas situaciones, las estructuras condicionales anidadas se pueden combinar en una sola estructura utilizando operadores lógicos. Si solo estuviéramos interesados en números pares positivos, por ejemplo, se podría usar una única estructura if
:
let my_number = 4;
if ( my_number > 0 && my_number % 2 == 0 )
{
console.log("The value of my_number is positive");
console.log("and it is an even number");
}
else
{
console.log("The value of my_number either 0, negative");
console.log("or it is a negative number");
}
El operador doble &&
en la expresión evaluada es el operador lógico AND. Se evalúa como verdadera solo si la expresión a su izquierda y la expresión a su derecha se evalúan como verdadera. Si desea hacer coincidir números que sean positivos o pares, se debe usar el operador ||
en su lugar, que representa el operador lógico OR:
let my_number = -4;
if ( my_number > 0 || my_number % 2 == 0 )
{
console.log("The value of my_number is positive");
console.log("or it is a even negative number");
}
En este ejemplo, solo los números impares negativos no cumplirán los criterios impuestos por la expresión compuesta. Si tiene la intención opuesta, es decir, para hacer coincidir solo los números impares negativos, agregue el operador lógico NOT !
al comienzo de la expresión:
let my_number = -5;
if ( ! ( my_number > 0 || my_number % 2 == 0 ) )
{
console.log("The value of my_number is an odd negative number");
}
Agregar el paréntesis en la expresión compuesta obliga a que la expresión encerrada entre ellos se evalúe primero. Sin estos paréntesis, el operador NOT se aplicaría solo a my_number > 0
y luego se evaluaría la expresión OR. Los operadores &&
y ||
se conocen como operadores lógicos binarios porque requieren dos operandos. !
se conoce como un operador lógico unario, porque solo requiere un operando.
Estructuras Switch
Aunque la estructura if
es bastante versátil y suficiente para controlar el flujo del programa, la estructura de control "switch" puede ser más apropiada cuando es necesario evaluar resultados que no sean verdaderos o falsos. Por ejemplo, si queremos tomar una acción distinta para cada elemento elegido de una lista, será necesario escribir una estructura if
para cada evaluación:
// Available languages: en (English), es (Spanish), pt (Portuguese)
let language = "pt";
// Variable to register whether the language was found in the list
let found = 0;
if ( language == "en" )
{
found = 1;
console.log("English");
}
if ( found == 0 && language == "es" )
{
found = 1;
console.log("Spanish");
}
if ( found == 0 && language == "pt" )
{
found = 1;
console.log("Portuguese");
}
if ( found == 0 )
{
console.log(language, " is unknown to me");
}
En este ejemplo, una variable auxiliar found
es utilizada por todas las estructuras if
para averiguar si se ha producido una coincidencia. En un caso como éste, la estructura switch
realizará la misma tarea, pero de una manera más breve:
switch ( language )
{
case "en":
console.log("English");
break;
case "es":
console.log("Spanish");
break;
case "pt":
console.log("Portuguese");
break;
default:
console.log(language, " not found");
}
Cada case
anidado se llama cláusula. Cuando una cláusula coincide con la expresión evaluada, ejecuta las declaraciones que siguen a los dos puntos hasta la declaración break
. La última cláusula no necesita una declaración break
y se usa a menudo para establecer la acción predeterminada cuando no ocurren otras coincidencias. Como se ve en el ejemplo, la variable auxiliar no es necesaria en la estructura switch
.
Warning
|
|
Si más de una cláusula desencadena la misma acción, puede combinar dos o más condiciones de case
:
switch ( language )
{
case "en":
case "en_US":
case "en_GB":
console.log("English");
break;
case "es":
console.log("Spanish");
break;
case "pt":
case "pt_BR":
console.log("Portuguese");
break;
default:
console.log(language, " not found");
}
Bucles
En ejemplos anteriores, las estructuras if
y switch
eran adecuadas para tareas que deben ejecutarse solo una vez después de pasar una o más pruebas condicionales. Sin embargo, hay situaciones en las que una tarea debe ejecutarse repetidamente, en un llamado bucle, siempre que su expresión condicional siga siendo verdadera. Si necesita saber si un número es primo, por ejemplo, deberá verificar si dividir ese número por cualquier número entero mayor que 1 y menor que él mismo tiene un resto igual a 0. Si es así, el número tiene un factor entero y no es primo. (Este no es un método riguroso o eficiente para encontrar números primos, pero funciona como un ejemplo simple). Las estructuras de controles de bucle son más adecuadas para tales casos, en particular, la instrucción while
:
// A naive prime number tester
// The number we want to evaluate
let candidate = 231;
// Auxiliary variable
let is_prime = true;
// The first factor to try
let factor = 2;
// Execute the block statement if factor is
// less than candidate and keep doing it
// while factor is less than candidate
while ( factor < candidate )
{
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
// The next factor to try. Simply
// increment the current factor by one
factor++;
}
// Display the result in the console window.
// If candidate has no integer factor, then
// the auxiliary variable is_prime still true
if ( is_prime )
{
console.log(candidate, "is prime");
}
else
{
console.log(candidate, "is not prime");
}
La declaración de bloque que sigue a la instrucción while
se ejecutará repetidamente siempre que la condición factor < candidate
sea verdadera. Se ejecutará al menos una vez, siempre que inicialicemos la variable factor
con un valor menor que candidate
. La estructura if
anidada en la estructura while
evaluará si el resto de candidate
dividido por factor
es cero. Si es así, el número de candidate
no es primo y el ciclo puede terminar. La instrucción break
finalizará el ciclo y la ejecución saltará a la primera instrucción después del bloque while
.
Tenga en cuenta que el resultado de la condición utilizada por la instrucción while
debe cambiar en cada bucle, de lo contrario, la instrucción de bloque se repetirá “para siempre”. En el ejemplo, incrementamos la variable factor
‒el siguiente divisor que queremos probar‒ y garantiza que el ciclo terminará en algún punto.
Esta sencilla implementación de comprobación de números primos funciona como se esperaba. Sin embargo, sabemos que un número que no es divisible por dos no será divisible por ningún otro número par. Por lo tanto, podríamos simplemente omitir los números pares agregando otra instrucción if
:
while ( factor < candidate )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
factor++;
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
// The next number that will divide the candidate
factor++;
}
La sentencia continue
es similar a la sentencia break
, pero en lugar de terminar esta iteración del ciclo, ignorará el resto del bloque del ciclo y comenzará una nueva iteración. Tenga en cuenta que la variable factor
se modificó antes de la declaración continue
, de lo contrario, el ciclo volvería a tener el mismo resultado en la siguiente iteración. Este ejemplo es demasiado simple y omitir parte del ciclo no mejorará realmente su rendimiento, pero omitir instrucciones redundantes es muy importante al escribir aplicaciones eficientes.
Los bucles se utilizan con tanta frecuencia que existen en muchas variantes diferentes. El ciclo for
es especialmente adecuado para iterar a través de valores secuenciales, porque nos permite definir las reglas del ciclo en una sola línea:
for ( let factor = 2; factor < candidate; factor++ )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
}
Este ejemplo produce exactamente el mismo resultado que el ejemplo anterior while
, pero su expresión entre paréntesis incluye tres partes, separadas por punto y coma: la inicialización (let factor = 2
), la condición de bucle (factor < candidate
) y la expresión final que se evaluará al final de cada iteración del ciclo (factor+`). Las declaraciones `continue` y `break` también se aplican a los bucles `for`. La expresión final entre paréntesis (`factor+
) se evaluará después de la instrucción continue
, por lo que no debería estar dentro de la instrucción del bloque, de lo contrario se incrementará dos veces antes de la siguiente iteración.
JavaScript tiene tipos especiales de bucles for
para trabajar con objetos similares a matrices. Podríamos, por ejemplo, verificar una matriz de variables candidatas en lugar de solo una:
// A naive prime number tester
// The array of numbers we want to evaluate
let candidates = [111, 139, 293, 327];
// Evaluates every candidate in the array
for (candidate of candidates)
{
// Auxiliary variable
let is_prime = true;
for ( let factor = 2; factor < candidate; factor++ )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
}
// Display the result in the console window
if ( is_prime )
{
console.log(candidate, "is prime");
}
else
{
console.log(candidate, "is not prime");
}
}
La declaración for (candidate of candidates)
asigna un elemento de la matriz candidates
a la variable candidate
y lo usa en la declaración de bloque, repitiendo el proceso para cada elemento de la matriz. No es necesario declarar candidate
por separado, porque el ciclo for
lo define. Finalmente, el mismo código del ejemplo anterior fue anidado en esta nueva declaración de bloque, pero esta vez probando cada candidato en la matriz.
Ejercicios guiados
-
¿Qué valores de la variable
my_var
coinciden con la condiciónmy_var > 0 && my_var < 9
? -
¿Qué valores de la variable
my_var
coinciden con la condiciónmy_var > 0 || my_var < 9
? -
¿Cuántas veces ejecuta el siguiente bucle
while
su declaración de bloque?let i = 0; while ( 1 ) { if ( i == 10 ) { continue; } i++; }
Ejercicios de exploración
-
¿Qué sucede si se usa el operador de asignación igual
=
en lugar del operador de comparación igual==
? -
Escriba un fragmento de código usando la estructura de control
if
donde una comparación de igualdad ordinaria devolverá verdadero, pero una comparación de igualdad estricta no lo hará. -
Reescriba la siguiente instrucción
for
utilizando el operador lógico unario NOT en la condición de bucle. El resultado de la condición debe ser el mismo.for ( let factor = 2; factor < candidate; factor++ )
-
Basado en los ejemplos de esta lección, escriba una estructura de control de bucle que imprima todos los factores enteros de un número dado.
Resumen
Esta lección cubre cómo usar estructuras de control en código JavaScript. Las estructuras condicionales y de bucle son elementos esenciales de cualquier paradigma de programación, y el desarrollo web JavaScript no es una excepción. La lección abarca los siguientes conceptos y procedimientos:
-
La instrucción
if
y los operadores de comparación. -
Cómo usar la estructura
switch
concase
,default
ybreak
. -
La diferencia entre comparación ordinaria y estricta.
-
Estructuras de control de bucle:
while
yfor
.
Respuestas a los ejercicios guiados
-
¿Qué valores de la variable
my_var
coinciden con la condiciónmy_var > 0 && my_var < 9
?Sólo números que son tanto mayores que 0 como menores que 9. El operador lógico
&&
(AND) requiere que ambas comparaciones coincidan. -
¿Qué valores de la variable
my_var
coinciden con la condiciónmy_var > 0 || my_var < 9
?El uso del operador lógico
||
(OR) hará que cualquier número coincida, ya que cualquier número será mayor que 0 o menor que 9. -
¿Cuántas veces ejecuta el siguiente bucle
while
su declaración de bloque?let i = 0; while ( 1 ) { if ( i == 10 ) { continue; } i++; }
The block statement will repeat indefinitely, as no stop condition was supplied.
Respuestas a los ejercicios de exploración
-
¿Qué sucede si se usa el operador de asignación igual
=
en lugar del operador de comparación igual==
?El valor del lado derecho del operador se asigna a la variable de la izquierda y el resultado se pasa a la comparación, que puede no ser el comportamiento deseado.
-
Escriba un fragmento de código usando la estructura de control
if
donde una comparación de igualdad ordinaria devolverá verdadero, pero una comparación de igualdad estricta no lo hará.let a = "1"; let b = 1; if ( a == b ) { console.log("An ordinary comparison will match."); } if ( a === b ) { console.log("A strict comparison will not match."); }
-
Reescriba la siguiente instrucción
for
utilizando el operador lógico unario NOT en la condición de bucle. El resultado de la condición debe ser el mismo.for ( let factor = 2; factor < candidate; factor++ )
Answer:
for ( let factor = 2; ! (factor >= candidate); factor++ )
-
Basándose en los ejemplos de esta lección, escriba una estructura de control de bucle que imprima todos los factores enteros de un número dado.
for ( let factor = 2; factor <= my_number; factor++ ) { if ( my_number % factor == 0 ) { console.log(factor, " is an integer factor of ", my_number); } }