¿Qué es Javascript?
JavaScript (abreviado comúnmente JS) es un lenguaje de programación interpretado, dialecto del estándar ECMAScript. Se define como orientado a objetos, basado en prototipos, imperativo, débilmente tipado y dinámico.Javascript es un lenguaje con muchas posibilidades, utilizado para crear pequeños programas que luego son insertados en una página web y en programas más grandes, orientados a objetos mucho más complejos. Con Javascript podemos crear diferentes efectos e interactuar con nuestros usuarios.
Este lenguaje posee varias características, entre ellas podemos mencionar que es un lenguaje basado en acciones que posee menos restricciones. Además, es un lenguaje que utiliza Windows y sistemas X-Windows, gran parte de la programación en este lenguaje está centrada en describir objetos, escribir funciones que respondan a movimientos del mouse, aperturas, utilización de teclas, cargas de páginas entre otros.
Es necesario resaltar que hay dos tipos de JavaScript: por un lado está el que se ejecuta en el cliente, este es el Javascript propiamente dicho, aunque técnicamente se denomina Navigator JavaScript. Pero también existe un Javascript que se ejecuta en el servidor, es más reciente y se denomina LiveWire Javascript.
Algunas características del lenguaje son:
Su sintaxis es similar a la usada en Java y C, al ser un lenguaje del lado del cliente este es interpretado por el navegador, no se necesita tener instalado ningún Framework.
- Variables:
var = “Hola”, n=103
- Condiciones:
if(i<10){ … }
- Ciclos:
for(i; i<10; i++){ … }
- Arreglos:
var miArreglo = new Array(“12”, “77”, “5”)
- Funciones: Ppopias del lenguaje y predefinidas por los usuarios
- Comentarios para una sola línea:
// Comentarios
- Comentarios para varias lineas:
/*
Comentarios
*/ - Permite la programación orientada a objetos:
document.write("Hola");
- Las variables pueden ser definidas como: string, integer, flota, bolean simplemente utilizando “
var
”. Podemos usar “+
” para concatenar cadenas y variables.
Diferencia entre Java y JavaScript
Java y JavaScript son lenguajes totalmente diferentes. He aquí algunos ejemplos importantes de sus muchas diferencias:
- JavaScript tradicionalmente ha sido un lenguaje interpretado, y Java es compilado. Para entendernos, y dicho muy básicamente, los programas JavaScript son archivos de texto que pueden leer tanto los ordenadores como las personas y que se interpretan a medida que se leen para luego ejecutarlos, mientras que los de Java se compilan a un archivo especial optimizado para que lo lea un ordenador y lo ejecute. Podríamos entrar en detalles de que Java se compila a un lenguaje intermedio llamado bytecode que es interpretado por un ejecutar JIT que facilita que sea multiplataforma, pero no es el objeto de este artículo y quiero mantenerlo intencionadamente simple. Por otro lado, y abundando en lo mismo, en la actualidad mucho código JavaScript es compilado (por ejemplo el motor V8 de Chrome y Node.js compila a código nativo el código JavaScript y puede llegar a ser tan rápido como cualquier otro). Así que en la actualidad la distinción no es tan clara entrando en detalle, pero sí se puede afirmar que son de naturaleza diferente porque JavaScript no requiere una compilación explícita para ser ejecutado.
- Java se depura en dos fases y JavaScript en una. Como con todos los lenguajes interpretados, en JavaScript solamente sabes si has cometido inadvertidamente un error de sintaxis cuando vas a ejecutar el programa (salvo que uses herramientas especializadas como Visual Studio o WebStorm, que interpretan el código en segundo plano). En Java sin embargo, primero se realiza la fase de compilación, en la que el compilador ya indica los posibles errores de sintaxis que existan. Luego al ejecutar podrían surgir errores de lógica o de otra índole. En JavaScript todos ellos se depuran al mismo tiempo, haciéndolo más complicado.
- Java es un lenguaje orientado a objetos puro, pero JavaScript está basado en prototipos. En realidad JavaScript debe simular muchas de las características de orientación a objetos que se dan en la mayoría de los lenguajes. A cambio proporciona diversos paradigmas de programación (funcional, imperativo, dinámico y orientado a objetos) lo que lo convierte en un lenguaje tremendamente versátil. De hecho en JavaScript es posible cambiar la "base" de la que hereda una clase en cualquier momento, afectando a todas, cosa imposible en la mayoría de los lenguajes orientados a objetos.
- Java es fuertemente tipado, y JavaScript es débilmente tipado. En Java todas las variables tienen un tipo determinado y una vez definidas no se pueden cambiar. En JavaScript una misma variable puede contener primero un texto, luego un número, luego una fecha o un objeto, etc... Esto es un arma de doble filo pues permite una gran flexibilidad a cambio de muchos posibles errores si no tenemos cuidado.
- Java tiene ámbito por bloque y JavaScript lo tiene por función: el acceso a las variables depende de dónde las hayamos definido. JavaScript tiene algunas reglas que pueden despistar bastante a los programadores de otros lenguajes.
- JavaScript tiene clausuras, Java las acaba de incorporar. Uno de los conceptos más importantes en la programación con JavaScript (y en otros lenguajes) son las clausuras. Java no las tuvo hasta la versión 8 aparecida hace muy poco tiempo, que añadió también las funciones lambda, para dar soporte al paradigma de programación funcional.
- Las funciones en JavaScript son multi-argumento siempre. En Java es necesario indicarlo.
- JavaScript es estándar, Java no. El control del lenguaje JavaScript lo lleva la organización sin ánimo de lucro European Computer Manufacturers Association (ECMA). De hecho su nombre oficial es ECMAScript, y está estandarizado. Por el contrario el control sobre Java lo tiene Oracle, una empresa privada que decide a su antojo lo que se hace con él.
¿Cómo identificar código Javascript?
El código javascript podemos encontrarlo dentro de las etiquetas <body></body> de nuestras páginas web. Por lo general se insertan entre: <script></script>. También pueden estar ubicados en en la etiqueta y ficheros externos usando:
<script type="text/javascript" src="micodigo.js"></script>
Estructura básica de JavaScript
Tipos de datos
Tipos de datos y las estrategias de consulta
Vamos a analizar cada una de estas estrategias con los diferentes tipos de datos de los que disponemos en Javascript y como se comportan en cada caso a fin de determinar la mejor estrategia en cada caso.
Tipos primitivos
Javascript tiene seis tipos primitivos:
- Sin definir (
undefined
) - Nulo (
null
) - Lógicos (
boolean
) - Numérico (
number
) - Cadena (
string
) - Símbolo (
symbol
)
Variable, constantes e identificadores
Operadores de asignaciónVariables
Una variable
var en lugar de let
Constantes
Constantes mayúsculas
Beneficios
Expresiones y operadores
Operadores
JavaScript tiene los siguientes tipos de operadores. Esta sección describe dichos operadores y contiene información sobre el orden de los mismos:
JavaScript tiene operadores binarios y unarios, y un operador ternario especial, el operador condicional. Un operador binario requiere dos operandos, uno antes del operador y otro después de este.
operando1 operador operando2
Por ejemplo,
3+4
o x*y
.
Un operador unario requiere solamente un operando, ya sea antes o después del operador:
operando operador
o
operador operando
Por ejemplo,
x++
o ++x
Un operador de asignación asigna un valor al operando de la izquierda en función del valor del operando de la derecha. El operador básico de asignación es el de igual
(=)
, que asigna el valor del operando de la derecha al operando de la izquierda. Por ejemplo, x = y,
está asignando el valor de y
a x.
También existen operadores compuestos de asignación que son la forma abreviada de las operaciones de la siguiente tabla:
Nombre | Operador abreviado | Significado |
---|---|---|
Operadores de asignación | x = y | x = y |
Asignación de adición | x += y | x = x + y |
Asignación de sustracción | x -= y | x = x - y |
Asignación de multiplicación | x *= y | x = x * y |
Asignación de división | x /= y | x = x / y |
Asignación de resto | x %= y | x = x % y |
Asignación de exponenciación | x **= y | x = x ** y |
Asignación de desplazamiento a la izquierda | x <<= y | x = x << y |
Asignación de desplazamiento a la derecha | x >>= y | x = x >> y |
Asignación de desplazamiento a la derecha sin signo | x >>>= y | x = x >>> y |
Asignación AND binaria | x &= y | x = x & y |
Asignación XOR binaria | x ^= y | x = x ^ y |
Asignación OR binaria | x |= y | x = x | y |
Destructuración
Para asignaciones mas complejas, la sintaxis de asignación con destructuración es una expresión de Javascript que permite extraer datos de arreglos u objetos usando una sintaxis que se asemeja a la contrucción de arreglos o objetos literales.
var foo = ['uno','dos','tres'];
// sin destructuración
var uno = foo[0];
var dos = foo[1];
var tres = foo[2];
// con destructuración
var [uno, dos, tres] = foo;
Operadores de comparación
Un operador de comparación compara sus operandos y devuelve un valor lógico en función de si la comparación es verdadera (
true
) o falsa (false
). Los operadores pueden ser númericos, de cadena de caracteres (Strings), lógicos o de objetos. Las cadenas de caracteres son comparadas basándose en un orden lexicográfico estándar, usando valores Unicode. En la mayoría de los casos, si los dos operandos no son del mismo tipo, JavaScriptintenta convertirlos en el tipo apropiado para permitir la comparación, generalmente esta conversión se realiza de manera numérica. Las únicas excepciones que tiene esta conversión son los operadores ===
y !==
que ejecutan comparaciones de igualdad o desigualdad de manera estricta (chequeando si ambos operandos son del mismo tipo). Estos operadores no intentan convertir los operandos a un tipo compatible antes de comprobar su igualdad. La siguiente tabla describe los operadores de comparación en base al siguiente código de ejemplo:
var var1 = 3;
var var2 = 4;
var var2 = 4;
Operador | Descripción | Ejemplos devolviendo true |
---|---|---|
Igualdad (== ) | Devuelve true si ambos operandos son iguales. | 3 == var1 "3" == var1 3 == "3" |
Desigualdad (!= ) | Devuelve true si ambos operandos no son iguales. | var1 != 4 |
Estrictamente iguales(=== ) |
Devuelve
true si los operandos son igual y tienen el mismo tipo. Mira también Object.is y sameness in JS. | 3 === var1 |
Estrictamente desiguales (!== ) |
Devuelve
true si los operandos no son iguales y/o no son del mismo tipo. | var1 !== "3" |
Mayor que (> ) |
Devuelve
true si el operando de la izquierda es mayor que el operando de la derecha. | var2 > var1 |
Mayor o igual que (>= ) | Devuelve true si el operando de la izquierda es mayor o igual que el operando de la derecha. | var2 >= var1 |
Menor que (< ) | Devuelve true si el operando de la izquierda es menor que el operando de la derecha. | var1 < var2 |
Menor o igual que (<= ) | Devuelve true si el operando de la izquierda es menor o igual que el operando de la derecha. | var1 <= var2 |
Operadores aritméticos
Los operadores aritméticos toman los valores númericos (tanto literales como variables) de sus operandos y devuelven un único resultado numérico. Los operadores aritméticos estandar son la suma
(+)
, la resta (-)
, la multiplicación (*)
y la división (/)
. Estos operadores funcionan como en la mayoría de los lenguajes de programación cuando son usados con números de coma flotante (en particular, tenga en cuenta que la división por cero produce Infinity
). Por ejemplo:1 / 2; // 0.5
1 / 2 == 1.0 / 2.0; // es true
Además de las operaciones de aritmética estándar (
+
, -
, *
y /
), JavaScript brinda los siguientes operadores aritméticos descritos en la tabla:Operador | Descripción | Ejemplo |
---|---|---|
Resto (% ) |
Operador binario correspondiente al módulo de una operación. Devuelve el resto de la división de dos operandos.
| 12 % 5 devuelve 2 . |
Incremento(++ ) |
Operador unario. Incrementa en una unidad al operando. Si es usado antes del operando
(++x) devuelve el valor del operando después de añadirle 1 y si se usa después del operando (x++) devuelve el valor de este antes de añadirle 1. | Si x es 3 , entonces ++x establece x a 4 y devuelve 4 , mientras que x++ devuelve 3 y, solo después de devolver el valor, establece x a 4 . |
Decremento (-- ) |
Operador unario. Resta una unidad al operando. Dependiendo de la posición con respecto al operando tiene el mismo comportamiento que el operador de incremento.
| Si x es 3 , entonces --x establece x a 2 y devuelve 2 , mientras que x-- devuelve 3 y, solo después de devolver el valor, establece x a 2 . |
Negación Unaria (- ) |
Operación unaria. Intenta convertir a número al operando y devuelve su forma negativa.
| -"3" devuelve -3 .-true devuelve -1 . |
Unario positivo (+ ) | Operación unaria. Intenta convertir a número al operando. | +"3" devuelve 3 .+true devuelve 1 . |
Exponenciación(** ) | Calcula la potencia de la base al valor del exponente. Es equivalente a baseexponente | 2 ** 3 devuelve 8 .10 ** -1 devuelve 0.1 . |
Operadores lógicosSección
Los operadores lógicos son comúnmente utilizados con valores booleanos; estos operadores devuelven un valor booleano. Sin embargo, los operadores &&
y ||
realmente devuelven el valor de uno de los operandos, asi que si estos operadores son usados con valores no booleanos, podrían devolveran un valor no booleano. En la siguiente tabla se describen los operadores lógicos:
&&
y ||
realmente devuelven el valor de uno de los operandos, asi que si estos operadores son usados con valores no booleanos, podrían devolveran un valor no booleano. En la siguiente tabla se describen los operadores lógicos:Operador | Uso | Descripción |
---|---|---|
AND Lógico (&&) | expr1 && expr2 |
Devuelve
expr1 si puede ser convertido a false de lo contrario devuelve expr2. Por lo tanto, cuando se usa con valores booleanos, && devuelve true si ambos operandos son true , en caso contrario devuelve false . |
OR Lógico(||) | expr1 || expr2 |
Devuelve
expr1 si puede ser convertido a true de lo contrario devuelve expr2. Por lo tanto, cuando se usa con valores booleanos, || devuelve true si alguno de los operandos es true , o false si ambos son false . |
NOT Lógico(!) | !expr |
Devuelve
false si su operando puede ser convertido a true , en caso contrario, devuelve true . |
Ejemplos de expresiones que pueden ser convertidas a
false
son aquellas que pueden ser evaluadas como null
, 0
, NaN
, undefined
o una cadena vacía.
El siguiente código muestra ejemplos del operador
&&
(AND Lógico).var a1 = true && true; // t && t devuelve true
var a2 = true && false; // t && f devuelve false
var a3 = false && true; // f && t devuelve false
var a4 = false && (3 == 4); // f && f devuelve false
var a5 = "Cat" && "Dog"; // t && t devuelve "Dog"
var a6 = false && "Cat"; // f && t devuelve false
var a7 = "Cat" && false; // t && f devuelve false
El siguiente código muestra ejemplos del operador
||
(OR Lógico).var o1 = true || true; // t || t devuelve true
var o2 = false || true; // f || t devuelve true
var o3 = true || false; // t || f devuelve true
var o4 = false || (3 == 4); // f || f devuelve false
var o5 = "Cat" || "Dog"; // t || t devuelve "Cat"
var o6 = false || "Cat"; // f || t devuelve "Cat"
var o7 = "Cat" || false; // t || f devuelve "Cat"
El siguiente código muestra ejemplos del operador
!
(NOT Lógico).var n1 = !true; // !t devuelve false
var n2 = !false; // !f devuelve true
var n3 = !"Cat"; // !t devuelve false
Evaluación mínima o evaluación de circuito corto
Como las expresiones lógicas son evaluadas de izquierda a derecha, estas son evaluadas de manera mínima (también llamada de circuito corto) usando las siguientes reglas:
false && algo
es mínimamente evaluada a false
.
true || algo
es mínimamente evaluada a true
.
Las reglas de la lógica garantizan que lan anteriores evaluaciones son siempre correctas. Nota que el operando algo
no es evaluado, por lo que situarlo no surte ningún efecto.
false && algo
es mínimamente evaluada a false
.true || algo
es mínimamente evaluada a true
.algo
no es evaluado, por lo que situarlo no surte ningún efecto.Operadores de cadenas de caracteres
Además de los operadores de comparación, que pueden ser usados en cadenas de caracteres, el operador de concatenación (+)
une dos valores de tipo String, devolviendo otro String correspondiente a la unión de los dos operandos.
Por ejemplo,
console.log("mi " + "string"); // lanza el String "mi string" en la consola.
La versión acortada de este operador de asignación (+=)
puede ser usada también para concatenar cadenas de caracteres.
Por ejemplo,
var mistring = "alfa";
mistring += "beto"; // devuelve "alfabeto" y asigna este valor a "mistring".
Además de los operadores de comparación, que pueden ser usados en cadenas de caracteres, el operador de concatenación
(+)
une dos valores de tipo String, devolviendo otro String correspondiente a la unión de los dos operandos.
Por ejemplo,
console.log("mi " + "string"); // lanza el String "mi string" en la consola.
La versión acortada de este operador de asignación
(+=)
puede ser usada también para concatenar cadenas de caracteres.
Por ejemplo,
var mistring = "alfa";
mistring += "beto"; // devuelve "alfabeto" y asigna este valor a "mistring".
Operador condicional (ternario)
El operador condicional es el único operador de JavaScript que necesita tres operandos. El operador asigna uno de dos valores basado en una condición. La sintaxis de este operador es:
condición ? valor1 : valor2
Si la condición es
true
, el operador tomará el valor1
, de lo contrario tomará el valor2
. Puedes usar el operador condicional en cualquier lugar que use un operador estándar.
Por ejemplo,
var estado = (edad >= 18) ? "adulto" : "menor";
Esta sentencia asigna el valor
adulto
a la variable estado
si edad
es mayor o igual a 18
, de lo contrario le asigna el valor menor
.Control de flujo y manejo de errores
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
Los bloques de sentencias son comúnmente utilizados para sentencias de control de flujo (ej.
if
, for
, while
).while (x < 10) {
x++;
}
En este caso
{ x++; }
es el 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 dado que la sentencia
var x
dentro del bloque está en el mismo ámbito que la sentencia var 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. Ver la referencia let
para más información.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; }
Aquí 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 evalúa true
y false
. Si la condición es verdadera, se ejecuta sentencia_1
; de lo contrario, se ejecuta sentencia_2
. La sentencia_1
y la sentencia_2
pueden ser cualquier sentencia, incluyendo otras sentencias anidadas en if
.
También puedes componer sentencias más complejas usando
else if
para tener múltiples 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; }
En el caso de condiciones múltiples solamente la primera condición lógica que evalúa a verdadero va a ser ejecutada. Para ejecutar múltiples sentencias, agruparlas 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; }
Es aconsejable no usar asignación simple dentro de una expresión condicional porque dicha asignación puede ser confundida con el comparador de igualdad cuando se lee de pasada el código. Por ejemplo, no usar el siguiente código:
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 evalúan como falso (también conocidos como valores Falsy):
false
undefined
null
0
NaN
- la cadena vacía (
""
)
El resto de valores, incluídos todos los objetos, son evaluados como verdadero cuando son pasados a una sentencia condicional.
No confundir los valores primitivos booleanos
true
y false
con los valores true y false del objeto Boolean
. Por ejemplo:var b = new Boolean(false);
if (b) // Esta condición se evalua a true
if (b == true) // Esta condición se evalua a false
Ejemplo
En el siguiente ejemplo, la función
comprobarDatos
devuelve true
si el número de caracteres en un objeto Text
es tres; en otro caso, muestra una alerta y devuelve false
.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 intentar 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 " + tipoFruta + ".");
}
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!"; } };
// Crear un tipo de objeto UserException
function UserException (aviso){
this.aviso=aviso;
this.nombre="UserException";
}
// Convertimos la excepción a String cuando es utilizada como un String
// (E.j: Un error de consola)
UserException.prototype.toString = function () {
return this.nombre + ': "' + this.aviso + '"';
}
// Crea una instancia del objeto y lo lanza
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 alguna 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 a continuación 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 identificador (catchID
en la sintaxis anterior) que tiene el valor especificado por la sentencia throw
; 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 estará 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 cuando 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 anidar 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); // muestra 'Error'
console.log(e.message); // muestra 'The message' o un error de JavaScript)
}
¿Qué es una función en JavaScript?
Cuando se desarrolla una aplicación compleja, es muy habitual utilizar una y otra vez las mismas instrucciones. Un script para una tienda de comercio electrónico por ejemplo, tiene que calcular el precio total de los productos varias veces, para añadir los impuestos y los gastos de envío.
Cuando una serie de instrucciones se repiten una y otra vez, se complica demasiado el código fuente de la aplicación, ya que:
- El código de la aplicación es mucho más largo porque muchas instrucciones están repetidas.
- Si se quiere modificar alguna de las instrucciones repetidas, se deben hacer tantas modificaciones como veces se haya escrito esa instrucción, lo que se convierte en un trabajo muy pesado y muy propenso a cometer errores.
Las funciones son la solución a todos estos problemas, tanto en JavaScript como en el resto de lenguajes de programación. Una función es un conjunto de instrucciones que se agrupan para realizar una tarea concreta y que se pueden reutilizar fácilmente.
En el siguiente ejemplo, las instrucciones que suman los dos números y muestran un mensaje con el resultado se repiten una y otra vez:
var resultado;
var numero1 = 3;
var numero2 = 5;
// Se suman los números y se muestra el resultado
resultado = numero1 + numero2;
alert("El resultado es " + resultado);
numero1 = 10;
numero2 = 7;
// Se suman los números y se muestra el resultado
resultado = numero1 + numero2;
alert("El resultado es " + resultado);
numero1 = 5;
numero2 = 8;
// Se suman los números y se muestra el resultado
resultado = numero1 + numero2;
alert("El resultado es " + resultado);
...
Aunque es un ejemplo muy sencillo, parece evidente que repetir las mismas instrucciones a lo largo de todo el código no es algo recomendable. La solución que proponen las funciones consiste en extraer las instrucciones que se repiten y sustituirlas por una instrucción del tipo "en este punto, se ejecutan las instrucciones que se han extraído":
var resultado;
var numero1 = 3;
var numero2 = 5;
/* En este punto, se llama a la función que suma
2 números y muestra el resultado */
numero1 = 10;
numero2 = 7;
/* En este punto, se llama a la función que suma
2 números y muestra el resultado */
numero1 = 5;
numero2 = 8;
/* En este punto, se llama a la función que suma
2 números y muestra el resultado */
...
Para que la solución del ejemplo anterior sea válida, las instrucciones comunes se tienen que agrupar en una función a la que se le puedan indicar los números que debe sumar antes de mostrar el mensaje.
Por lo tanto, en primer lugar se debe crear la función básica con las instrucciones comunes. Las funciones en JavaScript se definen mediante la palabra reservada
function
, seguida del nombre de la función. Su definición formal es la siguiente:function nombre_funcion() {
...
}
El nombre de la función se utiliza para llamar a esa función cuando sea necesario. El concepto es el mismo que con las variables, a las que se les asigna un nombre único para poder utilizarlas dentro del código. Después del nombre de la función, se incluyen dos paréntesis cuyo significado se detalla más adelante. Por último, los símbolos
{
y }
se utilizan para encerrar todas las instrucciones que pertenecen a la función (de forma similar a como se encierran las instrucciones en las estructuras if
o for
).
Volviendo al ejemplo anterior, se crea una función llamada
suma_y_muestra
de la siguiente forma:function suma_y_muestra() {
resultado = numero1 + numero2;
alert("El resultado es " + resultado);
}
Aunque la función anterior está correctamente creada, no funciona como debería ya que le faltan los "argumentos", que se explican en la siguiente sección. Una vez creada la función, desde cualquier punto del código se puede llamar a la función para que se ejecuten sus instrucciones (además de "llamar a la función", también se suele utilizar la expresión "invocar a la función").
La llamada a la función se realiza simplemente indicando su nombre, incluyendo los paréntesis del final y el carácter
;
para terminar la instrucción:function suma_y_muestra() {
resultado = numero1 + numero2;
alert("El resultado es " + resultado);
}
var resultado;
var numero1 = 3;
var numero2 = 5;
suma_y_muestra();
numero1 = 10;
numero2 = 7;
suma_y_muestra();
numero1 = 5;
numero2 = 8;
suma_y_muestra();
...
El código del ejemplo anterior es mucho más eficiente que el primer código que se mostró, ya que no existen instrucciones repetidas. Las instrucciones que suman y muestran mensajes se han agrupado bajo una función, lo que permite ejecutarlas en cualquier punto del programa simplemente indicando el nombre de la función.
Lo único que le falta al ejemplo anterior para funcionar correctamente es poder indicar a la función los números que debe sumar. Cuando se necesitan pasar datos a una función, se utilizan los "argumentos", como se explica en la siguiente sección.
Funciones con parámetros
Como ya indicamos en el capítulo anterior, los parámetros nos sirven para llamar a nuestras funciones con unos datos específicos para que los procese. Y en cada llamada, podemos darle unos parámetros diferentes, que harán que pueda comportarse de forma diferente, si ese es el comportamiento que le hemos programado.
var
numero = 1;var
cadena = "Hi!";var
logico = true;function
valores(num, cad, log) { document.write(num); document.write(cad); document.write(log); } valores(numero, cadena, logico);
Esta función la estamos llamando con variables como parámetros, pero también podemos llamar a la función con valores literales, es decir, valores simples directos:
valores(2, "adiós", false);
Como ya vimos en el capítulo anterior, también podemos hacer que otra función sea un parámetro:
valores(3, "que tal".length, true);
"que tal".length es una función que forma parte de los objetos de cadena de texto (todo, desde las variables hasta los literales, son objetos en JavaScript), y nos devuelve la longitud de una cadena de texto. En concreto, al hacer esta llamada nos devolverá un número '7'. Como las variables en JavaScript no tienen tipo (todas son objetos), podemos pasar cualquier valor como parámetro.
Devolución de datos
omo ya sabemos, una función puede devolver datos hacia afuera por medio de la expresión return. Naturalmente, podemos devolver cualquier tipo de datos. Sin embargo hay que tener en cuenta una serie de cuestiones:
- Siempre se devuelven objetos, como ya hemos visto, y por lo tanto podemos devolver un objeto creado en la misma función. Normalmente, cuando creamos una variable dentro de una función, esta variable existe sólo para esa función, y desaparece en el momento en que la función termina (la variable se encuentra en la pila de memoria, y cuando la función desaparece, también lo hace la pila); pero en el caso de que devolvamos el objeto, no se devuelve exactamente la misma variable, si no que se devuelve su contenido.
- Cuando devolvemos true ó un valor distinto que cero, para JavaScript es lo mismo, y si devolvemos false o 0, también viene a ser lo mismo. Esta es una regla estándar para muchos lenguajes como JavaScript, Java, PHP, Perl, etc...
- No es preciso que una función devuelva nada. No es necesario usar return. Además, también es posible que en vez de devolver resultados, se modifiquen variables globales, es decir, variables creadas fuera de la función y que se usan dentro.
- Si queremos salir de una función antes de tiempo, porque algo ha fallado o no hay nada que hacer en un caso específico, podemos simplemente escribir "return;", lo que nos permitirá salir sin más y no devolver ningún valor.
Estas consideraciones son importantes a nivel general y es importante tenerlas en cuenta. Vamos a ver como funcionan con algunos ejemplos:
function
dev_variable() { variable = true;return
variable; }var
var1 = dev_variable();
Como vemos, hemos declarado una variable local a la función y la hemos devuelto, pero solo se devuelve realmente el valor. Esto pasa en todos los casos (Nota técnica: cuando se devuelve un objeto, se devuelven sus datos en forma de objeto de esa clase; esto lo entenderemos mejor en el capítulo siguiente). Veamos este otro ejemplo:
function
dev_true() {return
true; }if
(dev_true()) { alert("es true"); }if
(true) { alert("también es true"); }if
(1) { alert("este también es true"); }
Por último, veamos cómo salir de una función sin necesidad de devolver nada en cualquier momento:
function
salir() { document.write("hola"); document.write("que pasa");return
; alert("adiós"); } salir();
En este ejemplo, la última linea dentro de la función (alert) no se ejecutará nunca porque hemos salido sin más en la linea anterior al ejecutarse la instrucción return.
Funciones recursivas
Las funciones recursivas son aquellas que se llaman a sí mismas. Existen multitud de técnicas para desarrollar este tipo de funciones, ya que sus usos son muy diversos, pero fundamentalmente hay que tener en consideración que son funciones peligrosas, porque si no controlamos su ejecución, se estarán ejecutando indefinidamente, como en el caso de los bucles infinitos. La diferencia con los bucles infinitos es que dependiendo de la implementación del intérprete de JavaScript, es posible que rompamos la pila de memoria, que ya vimos antes, con lo que además de colgar el navegador, podemos generar una excepción de memoria y un error grave del sistema. Para evitarlo, claro está, debemos estudiar bien la lógica de la función para construirla adecuadamente. Por ejemplo, si queremos calcular el factorial de un número, podemos hacerlo con una función recursiva:
function
factorial(numero) {if
(numero == 1 || numero == 0)return
1;else
return
numero*factorial(numero - 1); } document.write(factorial(4));
Supóngase la llamada a esta función para N=4, es decir factorial(4). Cuando se llame por primera vez a la función, la variable numero valdrá 4, y por tanto devolverá el valor de 4*factorial(3); pero factorial(3) devolverá 3*factorial(2); factorial(2) a su vez es 2*factorial(1) y dado que factorial(1) es igual a 1 (es importante considerar que sin éste u otro caso particular, llamado caso base, la función recursiva no terminaría nunca de llamarse a sí misma), el resultado final será 4*(3*(2*1)).
Funciones anónimas
Una función puede ser anónima, es decir, no tener un nombre.
var cuadrado = function(number) {
return number * number;
}
//Llamada a la función
var resultado = cuadrado(4);
//resultado vale ahora 16
Diferencia entre una función con nombre y una anónima
Cuando declaramos una función anónima no puede ser procesada hasta que el intérprete llegue a donde está declarada. El navegador va leyendo la página de arriba abajo, entonces la llamada a la función anónima debe estar siempre más abajo.
En cambio, si se trata de una función con nombre, el intérprete lo primero que hace es buscar las declaraciones las variables y funciones que puedan existir. Después comienza a leer línea por línea. De modo que podemos poner la llamada a una función antes de que ésta haya sido declarada.
Parámetros de funcion
Parámetro por defecto
En JavaScript, los parámetros de funciones están establecidos por defecto a
undefined
. Sin embargo, en ciertas situaciones puede ser útil establecerlos a un valor suministrado por defecto diferente. Es entonces cuando los parámetros por defecto pueden ayudar.
En el pasado, la estrategia general para establecer los parámetros por defecto era comprobar los valores de éstos en el cuerpo de la función y asignar un valor si estos eran
undefined
. Si en el siguiente ejemplo ningún valor es suministrado para b
durante el llamado, su valor sería undefined
cuando se evalúe a*b;
y la llamda de multiply
retornaría NaN
. Sin embargo, esto se evita con la segunda línea en este ejemplo:function multiply(a, b) {
b = typeof b !== 'undefined' ? b : 1;
return a*b;
}
multiply(5); // 5
Con los parámetros por defecto, la comprobación en el cuerpo de la función ya no es necesaria. Ahora, puede simplemente poner 1 como valor por defecto para
b
en la cabeza de la función.function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
Para más detalles, puede consultar parámetros por defecto en la referencia.
Parámetros rest
La syntaxis de parámetros rest (en inglés) nos permite respresentar un número indefinido de argumentos en forma de array. En el ejemplo, usamos los parámetros rest para recolectar los argumentos a partir del segundo y hasta el final. Entonces los multiplicamos por el primero. Este ejemplo está usando una función flecha, la cual es introducida en la siguiente sección.
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x);
}
var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
Funciones predefinidas por el lenguaje
La función eval
La función eval tiene como argumento una expresión y devuelve el valor de la misma. Esta función resulta útil para evaluar una cadena de caracteres que representa una expresión numérica. La edición efectuada mediante un campo de formulario es una cadena de caracteres que a veces es necesario convertir en valor numérico. El código siguiente ilustra este ejemplo permitiendo al usuario introducir una expreción numérica y visualiza a continuación el valor de la expresión.
<!-- Ejemplo: Función Eval--> |
Funciones escape y unescape
Estas dos funciones permiten codificar cadenas de caracteres en formato URL (ISO Latin 1). Esta codificación es necesaria en la creación automática de enlaces de hipertexto o en la definición de propiedades persistentes como los Cookies.
Ejemplo:
escape("He aquí")="He%20aquí"
unescape("He%20aquí")="He aquí"
escape("#"); // devuelve %23
unescape("%23"); // devuelve #
Ejemplo:
<!-- Ejemplo: Funciones Escape y Unescape--> |
Función parseFloat
Convierte un string a un número en punto flotante. Si se encuentra otros caracteres que no sean números, el signo '+', el '-' o un exponente, devuelve el valor encontrado hasta ese punto. Del mismo modo, si el primer caracter no se puede convertir a número devolverá cero.
parseFloat(cadena de caracteres)
Ejemplo:
<!-- Ejemplo: Función parseFloat--> |
La función isNaN
Comprueba si el valor pasado por parámetros es númerico o no. El resultado de esta función es un booleano. Es decir, evalúa un argumento para ver si es NaN: Not Number.
isNaN(valor de entrada)
Ejemplo:
<!-- Ejemplo: Función IsNann--> |
La función parseInt
Convierte una cadena de caracteres de entrada a un número entero con una base especificada. La base puede ser 8, 10 ó 16. Si se encuentra otros caracteres que no sean números, el signo '+', el '-' o un exponente, devuelve el valor encontrado hasta ese punto. Del mismo modo, si el primer caracter no se puede convertir a número devolverá cero.
parseInt(ristra,base) //base es opcional.
Ejemplo:
<!-- Ejemplo: Función parseInt--> |
Funciones anidadas y cierres
Puede anidar una función dentro de una función. La función anidada (inner) es privada a la función que la contiene (outer). También con la forma: aclosure.
- Un cierre es una expresión (normalmente una función) que puede tener variables libres junto con un entorno que enlaza esas variables (que "cierra" la expresión).
Dado que una función anidada es un cierre, esto significa que una función anidada puede "heredar" los argumentos y las variables de su función contenedora. En otras palabras, la función interna contiene el ámbito de la función externa.
function addCuadrado(a,b) {
function cuadrado(x) {
return x * x;
}
return cuadrado(a) + cuadrado(b);
}
a = addCuadrado(2,3); // retorna 13
b = addCuadrado(3,4); // retorna 25
c = addCuadrado(4,5); // retorna 41
function fuerade(x) {
function dentro(y) {
return x + y;
}
return dentro;
}
resultado = fuerade(3)(5); // retorna 8
No hay comentarios.:
Publicar un comentario