Este articulo necesita una revisión editorial. Cómo puedes ayudar.
Esta traducción está incompleta. Por favor, ayuda a traducir este artículo del inglés.
Javascript soporta un conjunto compacto de sentencias específicas para el manejo de flujo, que pueden ser utilizadas para incorporar mayor interactividad a tus aplicaciones. Este capítulo provee una vista general de las mismas.
La guía de referencia de Javascript contiene detalles exhaustivos sobre las sentencias mencionadas en este capítulo. El punto y coma (;
) se utiliza para separar sentencias de código Javascript.
En Javascript cualquier expresión es también una sentencia. Puedes ver Expresiones y operadores para más información sobre expresiones.
Sentencia de bloque
La sentencia de bloque es el tipo de sentencia más básico y se utiliza para agrupar sentencias. El bloque se delimita entre un par de llaves:
{ sentencia_1; sentencia_2; . . . sentencia_n; }
Ejemplo
El bloque es comúnmente utilizado para el control de flujo (ej. if
, for
, while
).
while (x < 10) { x++; }
En este caso { x++; }
es un bloque de sentencias.
Importante: Javascript no tiene ámbito a nivel bloque en versiones anteriores a ECMAScript 6. Las variables introducidas dentro de un bloque pertenecen a la función o script que lo contiene y el efecto de declararlas persiste más alla del bloque mismo. En otras palabras, los bloques no introducen un nuevo ámbito. Si bien los bloques "standalone" son válidos no deberían ser utilizados en Javascript ya que no se comportan como los bloques de C o Java. Por ejemplo:
var x = 1; { var x = 2; } console.log(x); // imprime 2
Este código imprime el número 2 ya que la sentencia de la variable x dentro del bloque está en el mismo ámbito que la variable x definida antes del bloque. En C o Java el equivalente de este código imprimiría 1.
A partir de ECMAScript 6, se introduce el ámbito a nivel bloque utilizando let
para declarar las variables.
Sentencias condicionales
Una sentencia condicional es un conjunto de comandos que se ejecutan si una condición es verdadera. JavaScript soporta dos sentencias condicionales: if...else
y switch
Sentencia if...else
Se utiliza la sentencia if
para comprobar si la condición lógica es verdadera. Se utiliza la opción else
para ejecutar un sentencia si la condición es falsa. A continuación se muestra un ejemplo de if...else
:
if (condición) { sentencia_1; } else { sentencia_2; }
La condición
puede ser cualquier expresión que se evalúa a true o false. Consultar Boolean para una explicación de como se evalua true
y false
. Si la condición es verdadera, sentencia_1
se ejecutra; si no, sentencia_2
se ejecuta. La sentencia_1
y la sentencia_2
pueden ser cualquier sentencia, incluyendo sentencias anidadas en if
.
Tambien puedes componer sentencias más complejas usando else if
para tener multiples condiciones, como se muestra a continuación:
if (condición_1) { sentencia_1; } else if (condición_2) { sentencia_2; } else if (condición_n) { sentencia_n; } else { ultima_sentencia; }
Para ejecutar multiples sentencias, agrupalas dentro de sentencias de bloque ({ ... }
) . En general, usar siempre sentencias de bloque es una buena práctica, sobre todo cuando se anidan sentencias if
:
if (condición) { ejecutar_sentencia_1_si_condición_es_verdadera; ejecutar_sentencia_2_si_condición_es_verdadera; } else { ejecutar_sentencia_3_si_condición_es_falsa; ejecutar_sentencia_4_si_condición_es_falsa; }
if (x = y) { /* sentencias aquí */ }
Si necesitas usar una asignación dentro de una expresión de condición, una práctica común es poner paréntesis adicionales alrededor de la asignación. Por ejemplo:
if ((x = y)) { /* sentencias aquí */ }
Valores falsos:
Los siguientes valores se evaluarán como falso (también conocidos como valores Falsy):
false
undefined
null
0
NaN
- la cadena vacía (
""
)
El resto de valores, incluidos todos los objetos, son evaluados como verdadero cuando son pasados a una sentencia condicional.
No confundir los valores primitivos booleanos true
y false
con el verdadero y falso del objeto Boolean
. Por ejemplo:
var b = new Boolean(false); if (b) // Esta condición se evalua a true
Ejemplo
En el siguiente ejemplo, la función comprobarDatos
devuelve verdadero si el número de caracteres en un objeto Text
es tres; en otro caso, muestra una alerta y devuelve falso.
function comprobarDatos() { if (document.form1.threeChar.value.length == 3) { return true; } else { alert("Introduce exactamente tres caracteres. " + document.form1.threeChar.value + " no es válido."); return false; } }
switch
Una sentencia switch
permite a un programa evaluar una expresión e intenta igualar el valor de dicha expresión a una etiqueta de caso (case). Si se encuentra una coincidencia, el programa ejecuta la sentencia asociada. Una sentencia switch
se describe como se muestra a continuación:
switch (expresión) { case etiqueta_1: sentencias_1 [break;] case etiqueta_2: sentencias_2 [break;] ... default: sentencias_por_defecto [break;] }
El programa primero busca una claúsula case
con una etiqueta que coincida con el valor de la expresión y, entonces, transfiere el control a esa cláusula, ejecutando las sentencias asociadas a ella. Si no se encuentran etiquetas coincidentes, el programa busca la cláusula opcional default
y, si se encuentra, transfiere el control a esa cláusula, ejecutando las sentencias asociadas. Si no se encuentra la cláusula default
, el programa continúa su ejecución por la siguiente sentencia al final del switch
. Por convención, la cláusula por defecto es la última cláusula, aunque no es necesario que sea así.
La sentencia opcional break
asociada con cada cláusula case
asegura que el programa finaliza la sentencia switch
una vez que la sentencia asociada a la etiqueta coincidente es ejecutada y continúa la ejecución por las sentencias siguientes a la sentencia switch. Si se omite la sentencia break
, el programa continúa su ejecución por la siguiente sentencia que haya en la sentencia switch
.
Ejemplo
En el siguiente ejemplo, si tipoFruta
se evalúa como "Plátanos", el programa iguala el valor con el caso "Plátanos" y ejecuta las sentencias asociadas. Cuando se encuentra la sentencia break
, el programa termina el switch
y ejecuta las sentencias que le siguen. Si la sentencia break
fuese omitida, la sentencia para el caso "Cerezas" también sería ejecutada.
switch (tipoFruta) { case "Naranjas": console.log("Naranjas cuestan 0,59€ el kilo."); break; case "Manzanas": console.log("Manzanas cuestan 0,32€ el kilo."); break; case "Plátanos": console.log("Plátanos cuestan 0,48€ el kilo."); break; case "Cerezas": console.log("Cerezas cuestan 3,00€ el kilo."); break; case "Mangos": console.log("Mangos cuestan 0,56€ el kilo."); break; case "Papayas": console.log("Mangos y papayas cuestan 2,79€ el kilo."); break; default: console.log("Disculpa, no tenemos el tipo de fruta " + fruittype + "."); } console.log("¿Te gustaría tomar algo?");
Sentencias de manejo de excepciones
Puedes lanzar excepciones usando la sentencia throw
y manejarlas usando las sentencias try...catch
.
Tipos de excepciones
Prácticamente cualquier objecto puede ser lanzado en JavaScript. Sin embargo, no todos los objetos lanzados son creados igual. Mientras que es bastante común para lanzar números o strings como errores, frecuentemente son más efectivos utilizar uno de los tipos de excepciones específicamente creados para este proposito:
Sentencia throw
Utiliza la sentencia throw
para lanzar una excepción. Cuando lanzas un excepción, se especifica la expresión que contiene el valor para ser lanzado:
throw expresión;
Puedes lanzar cualquier expresión, no solo expresiones de un tipo especifico. En el siguente código lanzamos varias excepciones de varios tipos:
throw "Error2"; // Tipo string throw 42; // Tipo número throw true; // Tipo booleano throw {toString: function() { return "¡Soy un objeto!"; } };
myUserException
del tipo UserException
y lo usa en la sentencia throw.// Crear un tipo de objeto UserException function UserException (aviso){ this.aviso=aviso; this.nombre="UserException"; } // Make the exception convert to a pretty string when used as a string // (e.g. by the error console) UserException.prototype.toString = function () { return this.nombre + ': "' + this.aviso + '"'; } // Create an instance of the object type and throw it throw new UserException("Value too high");
try...catch
La sentencia try...catch
marca un bloque de instrucciones a intentar que pueden causar alguna excepción, y declarar una o más respuestas en caso de que una excepción sea arrojada. Si una excepción es arrojada, la sentencia try...catch
se encarga de atraparla.
La sentencia try...catch
consiste en un bloque try
, el cuál contiene una o más instrucciones, y ninguno o varios bloques catch
, conteniendo sentencias que especifican que hacer si una excepción es arrojada en un bloque try
. Se desea que las instrucciones dentro del bloque try
se ejecuten con éxito, de caso contrario caerán en el bloque catch
para ser controladas. Si ninguna instrucción dentro del bloque try
(o en una función llamada dentro del bloque try
) arroja una excepción, el control pasa inmediatamente al bloque catch
. Si ninguna excepción es arrojada en el bloque try
, el bloque catch
es ignorado. Por último se ejecuta el bloque finally
luego de que los bloques try
y catch
hayan sido ejecutados pero antes de las instrucciones que se encuentren luego de la sentencia try...catch
.
El siguiente ejemplo usa la sentencia try...catch
. El ejemplo llama a una función que retorna el nombre de un mes desde un arreglo basado en un valor pasado como argumento a la función. Si el valor no corresponde con el número de un mes (entre 1 y 12), una excepción es arrojada con el valor "InvalidMonthNo
" y las instrucciones en el bloque catch
le asignarán a la variable monthName
el valor de unknown
.
function getMonthName (mo) { mo = mo-1; // Ajusta el indice del arreglo para el arreglo de meses (1=Jan, 12=Dec) var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul", "Aug","Sep","Oct","Nov","Dec"]; if (months[mo] != null) { return months[mo]; } else { throw "InvalidMonthNo"; //Arroja la palabra "InvalidMonthNo" al ocurrir una excepción } } try { // instrucciones a probar monthName = getMonthName(myMonth); // La función puede arrojar una excepción } catch (e) { monthName = "unknown"; logMyErrors(e); // Pasa el objeto de la excepción a un manejador de errores }
El bloque catch
Un bloque catch
es usado para manejar todas las excepciones que pueden ser generadas en el bloque try
.
catch (catchID) { instrucciones }
El bloque catch
especifica un identificar (catchID
en la sintaxis anterior) que mantiene el valor especificado por la sentencia thrown
; puedes usar este identificador para obtener información acerca de la excepción que fue arrojada. JavaScript crea este identificador cuando ha entrado en el bloque catch
; el identificador dura mientras dure el bloque catch
; después de que el bloque catch
termine su ejecución, el identificador ya no está disponible.
Por ejemplo, el siguiente código arroja una excepción. Cuando la excepción ocurre, el control es transferido al bloque catch
.
try { throw "myException" // genera una excepción } catch (e) { // instrucciones para manejar cualquier excepción generada logMyErrors(e) // Pasa el objeto de excepción a un manejador de errores }
El bloque finally
El bloque finally contiene instrucciones para ejecutar luego de la ejecución del bloque try
y el bloque catch
pero antes de las instrucciones ubicadas luego de la sentencia try...catch
. El bloque finally
se ejecuta se haya arrojado o no una excepción. Si una excepción es arrojada, las instrucciones en el bloque finally
se ejecutan incluso si no existe un bloque catch
que maneje la excepción.
Se puede usar el bloque finally
para hacer que tu script falle con gracia cuando una excepción ocurre; por ejemplo, puedes tener la necesidad de liberar un recurso que tu script tiene ocupado. El siguiente ejemplo abre un archivo y luego ejecuta instrucciones que usan el archivo (JavaScript del lado del servidor permite acceder a archivos). Si una excepción es arrojada mientras el archivo está abierto, el bloque finally
cierra el archivo antes de que el script falle.
openMyFile(); try { writeMyFile(theData); // Esto puede arrojar un error } catch(e) { handleError(e); // Si ocurre un error es manejado } finally { closeMyFile(); // Siempre cierra el recurso }
Si el bloque finally
retorna un valor, este valor se convierte en el valor de retorno de toda la sentencia try-catch-finally,
independientemente de cualquier sentencia return en el bloque try
y el bloque catch
:
function f() { try { console.log(0); throw "bogus"; } catch(e) { console.log(1); return true; // Esta sentencia de retorno es suspendida // hasta que el bloque finally esté completo console.log(2); // no alcanzable } finally { console.log(3); return false; // sobreescribe la sentencia de retorno anterior console.log(4); // no alcanzable } // "return false" es ejecutada ahora console.log(5); // no alcanzable } f(); // console 0, 1, 3; retorna false
Sobreescribiendo los valores retornados por el bloque finally también aplica a excepciones arrojadas o relanzadas dentro de un bloque catch:
function f() { try { throw "bogus"; } catch(e) { console.log('caught inner "bogus"'); throw e; // Esta sentencia throw es suspendida hasta que // el bloque finally se termine de ejecutar } finally { return false; // Sobreescribe la sentencia throw anterior } // "return false" es ejecutado ahora } try { f(); } catch(e) { // Esta nunca es encontrada porque la sentencia throw dentro // del bloque catch es sobrescrita por la sentencia return // en el bloque finally console.log('caught outer "bogus"'); } // SALIDA // atrapado dentro de "bogus"
Sentencias try...catch
anidadas
Es posible anidad una o más sentencias try...catch
. Si una sentencia try...catch
interna no posee un bloque catch
, la sentencia try...catch
exterior verifica si el bloque exterior genera una coincidencia.
Utilizando objetos de Error
Dependiendo del tipo de error, es posible usar el 'name' (nombre) y el 'message' (mensaje) propiedades para obtener un mensaje más refinado. La propiedad 'name' provee la clase general del Error(por ejemplo, 'DOMException' or 'Error'), mientras que la propiedad 'message' por lo general provee un breve mensaje que puede ser obtenido convirtiendo el error de object a string.
Si estás arrojando tus propias excepciones, en orden para tomar ventaja de estas propiedades (Como si tu bloque catch no discrimina entre tus propias excepciones y las excepciones del sistema), puedes usar el constructor de Error. Por ejemplo:
function doSomethingErrorProne () { if (ourCodeMakesAMistake()) { throw (new Error('The message')); } else { doSomethingToGetAJavascriptError(); } } .... try { doSomethingErrorProne(); } catch (e) { console.log(e.name); // logs 'Error' console.log(e.message); // logs 'The message' o un error de JavaScript) }
Promises
Empezando con ECMAScript 6, Javascript gana soporte para Promise
objetos que permiten tomar el control del flujo o diferidas operaciones asincronas.
Una Promise
puede estar ubicada en estos estados:
- pending: Estado inicial, ni terminada exitosamente o rechazada.
- fulfilled: operación exitosa.
- rejected: operación fallida o rechazada.
- settled: la Promise ha sido exitosa o rechazada, pero no está pendiente.
Cargando una imagen con XHR
Un simple ejemplo del uso de Promise
y XMLHttpRequest es cargar una imagen que está disponible en el repositorio promise-test de MDN GitHub. Puedes verlo también en acción. Cada paso es comentado y permite que sigas la arquitectura de la Promise y XHR de cerca. Aquí está una versión sin comentar, mostrando el flujo de una Promise
para que puedas tener una idea:
function imgLoad(url) { return new Promise(function(resolve, reject) { var request = new XMLHttpRequest(); request.open('GET', url); request.responseType = 'blob'; request.onload = function() { if (request.status === 200) { resolve(request.response); } else { reject(Error('Image didn\'t load successfully; error code:' + request.statusText)); } }; request.onerror = function() { reject(Error('There was a network error.')); }; request.send(); }); }
Para información más detallada, visitar Promise
como página de referencia.