Ver índice de contenidos del libro

3.3. Otros conceptos

3.3.1. Excepciones

JavaScript dispone de un mecanismo de tratamiento de excepciones muy similar al de otros lenguajes de programación como Java. Para ello, define las palabras reservadas try, catch y finally.

La palabra reservada try se utiliza para encerrar el bloque de código JavaScript en el que se van a controlar las excepciones. Normalmente, el bloque definido por try va seguido de otro bloque de código definido por catch.

Cuando se produce una excepción en el bloque try, se ejecutan las instrucciones contenidas dentro del bloque catch asociado. Después del bloque catch, es posible definir un bloque con la palabra reservada finally. Todo el código contenido en el bloque finally se ejecuta independientemente de la excepción ocurrida en el bloque try.

Un bloque try debe ir seguido obligatoriamente de un bloque catch o de un bloque finally. También es posible que vaya seguido de los dos bloques.

A continuación se muestra un ejemplo de excepción y uso de los bloques try y catch:

try {
  var resultado = 5/a;
} catch(excepcion) {
  alert(excepcion);
}

El bloque catch permite indicar el nombre del parámetro que se crea automáticamente al producirse una excepción. Este identificador de la variable sólo está definido dentro del bloque catch y se puede utilizar para obtener más información sobre la excepción producida.

En este caso, al intentar dividir el número 5 por la variable a que no está definida, se produce una excepción que muestra el siguiente mensaje dentro del bloque catch:

Excepción JavaScript provocada por una variable no definida

Figura 3.1 Excepción JavaScript provocada por una variable no definida

El funcionamiento del bloque finally no es tan sencillo como el bloque catch. Si se ejecuta cualquier parte del código que se encuentra dentro del bloque try, siempre se ejecuta el bloque finally, independientemente del resultado de la ejecución del bloque try.

Si dentro del bloque try se ejecuta una instrucción de tipo return, continue o break, también se ejecuta el bloque finally antes de ejecutar cualquiera de esas instrucciones. Si se produce una excepción en el bloque try y están definidos los bloques catch y finally, en primer lugar se ejecuta el bloque catch y a continuación el bloque finally.

JavaScript también permite lanzar excepciones manualmente mediante la palabra reservada throw:

try {
  if(typeof a == "undefined" || isNaN(a)) {
    throw new Error('La variable "a" no es un número');
  }
  var resultado = 5/a;
} catch(excepcion) {
  alert(excepcion);
} finally {
  alert("Se ejecuta");
}

En este caso, al ejecutar el script se muestran los dos siguientes mensajes de forma consecutiva:

Manejando las excepciones en JavaScript para mostrar mensajes al usuario

Figura 3.2 Manejando las excepciones en JavaScript para mostrar mensajes al usuario

El bloque "finally" siempre se ejecuta cuando se produce una excepción en JavaScript

Figura 3.3 El bloque "finally" siempre se ejecuta cuando se produce una excepción en JavaScript

3.3.2. Clausura (closure)

El concepto de clausura closure en inglés) es conocido y utilizado en varios lenguajes de programación desde hace décadas. JavaScript también permite utilizar clausuras en el código de las aplicaciones. En este caso, las clausuras se crean de forma implícita, ya que no existe ninguna forma de declararlas explícitamente.

A continuación se muestra un ejemplo sencillo de clausura en JavaScript:

var x = "estoy fuera";
 
function funcionExterna() {
  var x = "estoy dentro";
  function funcionAnidada() { alert(x); }
  funcionAnidada();
}
 
funcionExterna();

Al ejecutar el código anterior, se muestra el mensaje "estoy dentro". Cuando se define una función dentro de otra, todas las variables de la primera función están disponibles de forma directa en la función anidada.

Técnicamente, una clausura es una porción de código (normalmente una función) que se evalúa en un entorno de ejecución que contiene variables de otro entorno de ejecución. JavaScript crea clausuras para todas las funciones definidas dentro de otra función. Sin embargo, el uso expreso de clausuras es muy limitado y se reserva sólo para las técnicas más avanzadas y complejas de JavaScript. Utilizando clausuras es posible por ejemplo simular el funcionamiento de las propiedades privadas en los objetos de JavaScript.

Existen recursos online con una explicación detallada del funcionamiento y aplicaciones de las clausuras en JavaScript, como por ejemplo http://www.jibbering.com/faq/notes/closures/

3.3.3. Reflexión

Al igual que la mayor parte de los lenguajes de programación más utilizados, JavaScript define mecanismos que permiten la reflexión sobre los objetos. La reflexión es un proceso mediante el cual un programa es capaz de obtener información sobre si mismo y por tanto es capaz de auto modificarse en tiempo de ejecución.

JavaScript emplea el concepto de reflexión para permitir descubrir propiedades y métodos de objetos externos. El ejemplo más sencillo es el de averiguar si un objeto posee un determinado método y así poder ejecutarlo. Si se dispone de un objeto llamado elObjeto, el código necesario para descubrir si posee una determinada propiedad llamada laPropiedad sería el siguiente:

if(elObjeto.laPropiedad) {
  // el objeto posee la propiedad buscada
}

Si el objeto no dispone de la propiedad buscada, la respuesta será undefined, que se transformará en un valor false que hace que no se ejecute el interior del bloque if.

Sin embargo, el código anterior no es del todo correcto, ya que si la propiedad buscada tiene un valor de false, null o el número 0, el anterior código no se ejecutará correctamente. En tal caso, el código necesario es el siguiente:

if(typeof(elObjeto.laPropiedad) != 'undefined') {
  // el objeto posee la propiedad buscada
}

El ejemplo anterior hace uso del operador typeof, que devuelve el tipo del objeto o variable que se le pasa como parámetro. Los valores que devuelve este operador son: undefined, number, object, boolean, string o function.

El otro operador que ya se comentó anteriormente es instanceof, que comprueba si un objeto es una instancia de otro objeto:

if(elObjeto instanceof Factura) {
  alert("Se trata de un objeto de tipo Factura");
}

Este operador también se puede emplear con objetos nativos de JavaScript:

var elObjeto = [];
if(elObjeto instanceof Array) {
  alert("Es un array");
}
else if(elObjeto instanceof Object) {
  alert("Es un objeto");
}

En el ejemplo anterior, el programa muestra por pantalla el mensaje "Es un array" ya que se cumple la primera comprobación por ser la variable elObjeto un array. Sin embargo, si se cambia de orden las comprobaciones:

var elObjeto = [];
if(elObjeto instanceof Object) {
  alert("Es un objeto");
}
else if(elObjeto instanceof Array) {
  alert("Es un array");
}

En este caso, la salida del programa es el mensaje "Es un objeto". El motivo es que, a pesar de que JavaScript no soporta el concepto de herencia en los objetos definidos a medida, los objetos nativos Function y Array sí que heredan del objeto Object. Así, la comprobación elObjeto instanceof Object devuelve un valor true, por ser Array una clase que hereda de Object.

Ejercicio 6

Sobrescribir el objeto Object para que incluya un método llamado implementa() y que indique si el objeto posee el método cuyo nombre se le pasa como parámetro.

Ver solución