https://manuais.iessanclemente.net/index.php?title=Funciones_en_JavaScript&feed=atom&action=historyFunciones en JavaScript - Historial de revisiones2024-03-29T04:45:06ZHistorial de revisiones de esta página en el wikiMediaWiki 1.36.2https://manuais.iessanclemente.net/index.php?title=Funciones_en_JavaScript&diff=69799&oldid=prevVieites: /* try/catch/finally */2021-09-26T16:12:06Z<p><span dir="auto"><span class="autocomment">try/catch/finally</span></span></p>
<p><b>Página nueva</b></p><div>[https://developer.mozilla.org/es/docs/Web/JavaScript/Guide/Funciones Una función es un bloque de código JavaScript] que se define una vez pero que se puede ejecutar o llamar varias veces. Las funciones pueden tener '''parámetros''', que son '''variables locales''' cuyo valor se especifica cuando se llama a la función.<br />
<br />
Cuando se llama a una función en un objeto, la función se denomina '''método''' y el objeto en el que se invoca se pasa como argumento implícito de la función.<br />
<br />
Ahora nos centraremos en ver cómo se definen y se llaman a nuestras propias funciones en JavaScript pero, sin olvidar, que JavaScript admite también "funciones integradas", como '''eval()''', '''parseInt()''' y el método '''sort()''' de la clase ''Array''. Además, JavaScript define otras funciones en el navegador, como '''document.write()''' y '''alert()''' tal y como iremos viendo a lo largo del curso.<br />
<br />
== Definición y llamada de funciones ==<br />
El método más fácil de definir una función es utilizar la instrucción '''function'''. Veamos unos ejemplos:<br />
<source lang="javascript"><br />
// Una función de acceso rápido, <br />
//útil a veces en lugar de document.write()<br />
// Esta función no tiene una instrucción return, <br />
//por lo que devuelve undefined.<br />
function print(msg) {<br />
document.write(msg, ‘<br>’);<br />
}<br />
<br />
// Una función que calcula y devuelve <br />
//la distancia comprendida entre dos puntos<br />
function distancia(x1, y1, x2, y2) {<br />
let dx = x2 - x1;<br />
let dy = y2 - y1;<br />
return Math.sqrt(dx*dx + dy*dy);<br />
}<br />
<br />
//Una función recursiva (que se llama a sí misma) <br />
//que calcula factoriales.<br />
function factorial(x) {<br />
if (x <= 1) { return 1; }<br />
return x * factorial(x-1);<br />
}<br />
</source><br />
<br />
Con un código como el siguiente podemos llamar a las funciones definidas en el listado anterior:<br />
<source lang="javascript"><br />
print("Hola, " + nombre);<br />
print("Hola caracola");<br />
total_dist = distancia(0, 0, 2, 1) + distancia(2, 1, 3, 5);<br />
print("La probabilidad es: " + factorial(5)/factorial(13));<br />
</source><br />
<br />
Como JavaScript es un lenguaje de establecimiento flexible de tipos, no es necesario que se especifique un tipo de datos para los parámetros de la función y JavaScript no comprueba si hemos pasado el tipo de datos que espera la función. Si el tipo de datos de un argumento es importante, podemos comprobar dicho tipo con el operador '''typeof'''.<br />
<br />
JavaScript tampoco comprueba si hemos pasado la cantidad correcta de argumentos. Si pasamos más argumentos de los esperados por la función, ésta ignora los adicionales. Si pasamos menos argumentos de los esperados, los parámetros que hemos omitido tienen un valor '''undefined'''.<br />
<br />
:: '''Veremos a continuación cómo se puede determinar exactamente la cantidad de argumentos que se le pasa a una función y a acceder a dichos argumentos por su posición en la lista de argumentos en lugar de por su nombre.'''<br />
<br />
== Denominación de funciones ==<br />
Normas básicas:<br />
* Los nombres de las funciones son normalmente verbos o frases que empiezan con verbos.<br />
* Es normal que los nombres de función empiecen con letras minúsculas.<br />
* Cuando un nombre incluye múltiples palabras, una convención utilizada con frecuencia es utilizar palabras separadas por guiones bajos, como en '''guardar_documento()'''.<br />
* Otro convenio es empezar todas las palabras distintas con letras mayúsculas tras la primera palabra, como en '''guardarDocumento()'''.<br />
* Las funciones que se supone que son internas o están ocultas, a veces tienen nombres que empiezan con un signo de subrayado '''( _ )'''.<br />
<br />
== Instrucciones utilizadas en el interior de las funciones ==<br />
=== '''return''' ===<br />
La instrucción '''return''' especifica el valor devuelto por una función. La sintaxis de la instrucción '''return''' es:<br />
<source lang="javascript"><br />
return expresión;<br />
</source><br />
Una instrucción '''return''' sólo puede aparecer dentro del cuerpo de una función. Será un error de sintaxis que aparezca en cualquier otro lugar.<br />
<br />
Cuando se ejecuta la instrucción '''return''', se evalúa la expresión y se devuelve como valor de la función y, claro está, se detiene la ejecución de dicha función, incluso aunque quede alguna otra instrucción en el cuerpo de la misma.<br />
<br />
Veamos un ejemplo:<br />
<source lang="javascript"><br />
function cuadrado(x) { return x*x; }<br />
</source><br />
<br />
Si una función ejecuta una instrucción '''return''' sin devolver nada, el valor de la expresión de llamada de la función es '''undefined'''.<br />
<br />
=== '''throw''' ===<br />
Una excepción es una señal que indica que se ha producido algún tipo de condición o error excepcional. <br />
* Lanzar una excepción será señalar dicho error o condición excepcional.<br />
* En el momento que se lanza una excepción la función termina indicando el error producido, a no ser que esa excepción sea "capturada".<br />
* Capturar una excepción es controlarla, llevar a cabo cualquier acción necesaria o apropiada para recuperarse de la excepción.<br />
* En JavaScript, las excepciones se lanzan siempre que se produce un error en tiempo de ejecución y cuando un programa lanza explícitamente una excepción utilizando la instrucción '''throw'''.<br />
* Las excepciones se capturan con la instrucción '''try/catch/finally''', tal y como veremos luego.<br />
<br />
La instrucción '''throw''' tiene la siguiente sintaxis:<br />
<source lang="javascript"><br />
throw expresión;<br />
</source><br />
<br />
La "expresión" puede ser "de cualquier tipo" pero, normalmente, es un objeto '''Error''' o una instancia de una de sus subclases (también veremos este objeto posteriormente). También es útil lanzar una cadena con un mensaje de error o un valor numérico (código de error). <br />
Veamos un ejemplo:<br />
<source lang="javascript"><br />
function factorial(x) {<br />
if (isNaN(parseInt(x)) || x < 0) throw new Error("Sólo números positivos");<br />
//Seguimos con el cálculo si son positivos<br />
for (var f = 1; x > 1; f *= x, x--); //Funcionaría esta función con "let f = 1..."?<br />
return f; }<br />
</source><br />
Cuando se lanza una excepción, el intérprete de JavaScript detiene inmediatamente la ejecución normal del programa y salta al controlador de excepción más cercano. Los controladores de excepción se escriben utilizando la cláusula '''catch''' de la instrucción '''try/catch/finally''', que luego se describe. Si no se encuentra ningún controlador de excepción, ésta se trata como un error y se informa al usuario.<br />
<br />
=== '''try/catch/finally''' ===<br />
La instrucción '''try/catch/finally''' es un mecanismo de control de excepciones de JavaScript. Veamos, a continuación, un código que ilustra la sintaxis y el propósito de la instrucción '''try/catch'''. En particular, hay que observar que a la palabra '''catch''' le sigue un identificador entre paréntesis. Este identificador es como un argumento de función. Denomina una variable local que existe sólo dentro del cuerpo del bloque '''catch'''. JavaScript asigna a esta variable cualquier objeto o valor de excepción.<br />
<source lang="javascript"><br />
//Función que recorre los elementos de un array<br />
function factorial(x) {<br />
try {<br />
if (isNaN(parseInt(x)) || x < 0) throw new Error("Sólo números positivos");<br />
//Seguimos con el cálculo si son positivos<br />
for (var f = 1; x > 1; f *= x, x--); //Funcionaría esta función con "let f = 1..."?<br />
return f; }<br />
//Se guarda la excepción anterior en la variable local 'erro'<br />
catch(erro) { return erro; }<br />
//Y el bloque finally se ejecuta siempre<br />
finally { console.log("Este mensaje se ve siempre!!"); }<br />
}<br />
let n = prompt("Introduce número", "");<br />
alert("El factorial de " + n + " es " + factorial(n));<br />
</source><br />
<br />
Este ejemplo es una instrucción '''try/catch/finally''', aunque '''finally''' no se utiliza tan a menudo como '''catch''', con frecuencia puede ser útil. Independientemente de cómo se complete el código en el bloque '''try''', está garantizado que la cláusula '''finally''' se va a ejecutar si se ejecuta cualquier parte de dicho bloque. Generalmente se utiliza para limpiar tras el código de la cláusula '''try'''. Resumiendo, normalmente, el control llega al final del bloque '''try''' y, después, procede con el bloque '''finally''' que ejecuta cualquier limpieza necesaria. <br />
<br />
También saber que, si el control deja el bloque '''try''' por una instrucción '''return''', '''continue''' o '''break''', se ejecuta siempre el bloque '''finally''' antes de que el control se transfiera a su nuevo destino.<br />
<br />
== Argumentos de función ==<br />
Los argumentos de una función se guardan en un objeto '''Arguments''' denominado '''arguments''', parecido a una matriz, desde donde podremos acceder a cada uno de ellos por número (posición), no por nombre. El identificador '''arguments''', como cualquier matriz, tiene la propiedad '''length''' que especifica el número de elementos que contiene.<br />
<br />
En el siguiente ejemplo se demuestra el uso de '''arguments''' para verificar que se llama a una función con la cantidad correcta de argumentos, ya que JavaScript no lo hace automáticamente:<br />
<source lang="javascript"><br />
function f(x, y, z) {<br />
// Se comprueba número de argumentos<br />
if (arguments.length != 3) {<br />
throw new Error("Se esperaban 3 argumentos"); }<br />
// Aquí escribimos el cuerpo de la función…<br />
}<br />
</source><br />
[[Archivo:funcionesJS01.png|600px|centro|Error función número argumentos.]]<br />
<br />
Podemos escribir una función que trabaje con cualquier número de argumentos. Veamos un ejemplo en el que se crea una función '''max()''' que devuelve el valor del argumento más grande que se le pase (la función '''Math.max()''' se comporta de la misma forma):<br />
<source lang="javascript"><br />
function max() {<br />
let n = 0;<br />
let m = Number.NEGATIVE_INFINITY;<br />
// Recorrer con un bucle todos los argumentos<br />
//buscando y recordando el más grande<br />
for (let i = 0; i < arguments.length; i++) {<br />
n = parseInt(arguments[i]);<br />
if (n > m) m = n; }<br />
// Devolver el más grande<br />
return m;<br />
}<br />
let largest = max(1, 10, 23, 45, 33, 23, 11, 55, 2, 0);<br />
console.log(largest);<br />
</source><br />
<br />
Crear una función que devuelva la suma de todos esos argumentos.<br />
<source lang="javascript"><br />
function sumAll() {<br />
let sum = 0;<br />
for (let i = 0; i < arguments.length; i++) {<br />
sum += parseInt(arguments[i]);<br />
}<br />
return sum;<br />
}<br />
let suma = sumAll(1, 10, 23, 45, 33, 23, 11, 55, 2, 0);<br />
console.log (suma);<br />
</source><br />
<br />
=== Paso de múltiples argumentos ===<br />
Cuando una función requiere más de tres argumentos, es interesante poder hacer que los argumentos se pasen como pares nombre/valor y en cualquier orden. Para implementar este tipo de invocación de método, debemos definir nuestra función para que espere un solo objeto como su argumento y, posteriormente, dejar que los usuarios de la función pasen un literal de objeto que defina los pares de nombre/valor requeridos.<br />
<br />
'''Nos pararemos en estas funciones cuando veamos Objetos en un apartado posterior.'''<br />
<br />
=== Funciones como datos ===<br />
En JavaScript, las funciones no son sólo sintaxis sino también datos, lo que significa que se pueden asignar a variables, guardarse en las propiedades de los objetos o de los elementos de matrices, pasarse como argumentos a funciones, etc.<br />
<source lang="javascript"><br />
function square(x) { return x*x; }<br />
let a = square(4) // "a" contiene el número 16<br />
let b = square; // "b" hace referencia a la misma función square<br />
let c = b(5); // "c" contiene el número 25<br />
</source><br />
<br />
Las funciones también se pueden asignar a propiedades de un objeto en lugar de a variables globlales. Así las funciones se denominan métodos:<br />
<source lang="javascript"><br />
let o = new Object;<br />
o.square = function(x) { return x*x; }<br />
let y = o.square(16); // y es igual a 256<br />
</source><br />
<br />
Las funciones ni siquiera requieren un nombre si se asignan a elementos de una matriz:<br />
<source lang="javascript"><br />
let a = new Array(3);<br />
a[0] = function(x) { return x*x; }<br />
a[1] = 20;<br />
a[2] = a[0](a[1]); //"a[2]" contiene el número 400<br />
</source><br />
<br />
Podemos ver en los dos ejemplos siguientes cómo se pueden pasar funciones como argumentos de otras funciones y lo útil que puede ser esta técnica a la hora de programar en JavaScript.<br />
Ejemplo simple:<br />
<source lang="javascript"><br />
//Definimos algunas funciones simples<br />
function sumar(x,y) { return x + y; }<br />
function restar(x,y) { return x - y; }<br />
function multiplicar(x,y) { return x * y; }<br />
function dividir(x,y) { return x / y; }<br />
//Definimos una función que acepta como argumento<br />
//una de las definidas antes<br />
function operar(operador, operando1, operando2) {<br />
return operador(operando1, operando2);<br />
}<br />
//Solucionar la ecuación : (2+3) + (4*5)<br />
let i = operar(sumar, operar(sumar,2,3), operar(multiplicar,4,5));<br />
//Mostramos la salida<br />
console.log(i);<br />
</source><br />
<br />
Ejemplo más complejo:<br />
<source lang="javascript"><br />
//Definimos algunas funciones simples<br />
//como elementos de un objeto diccionario<br />
let operadores = {<br />
sumar : function sumar(x,y) { return x + y; },<br />
restar : function restar(x,y) { return x - y; },<br />
multiplicar : function multiplicar(x,y) { return x * y; },<br />
dividir : function dividir(x,y) { return x / y; },<br />
cuadrado : Math.pow //También con predefinidas<br />
}<br />
//Función que llama a una función desde su operador<br />
function operar(nombreOperador, operando1, operando2) {<br />
if (typeof operadores[nombreOperador] == "function")<br />
return operadores[nombreOperador](operando1, operando2);<br />
else throw "Operador NO conocido";<br />
}<br />
<br />
//Ejemplo de llamada de esta función: (2+3) + (4*5)<br />
let i = operar("sumar", operar("sumar",2,3), operar("multiplicar",4,5));<br />
//Mostramos la salida<br />
console.log(i);<br />
</source><br />
<br />
== Funciones anónimas ==<br />
Son funciones sin un nombre o identificador. Debido a esto, se pueden pasar a otras funciones o asignar a variables. Cuando una función anónima se asigna a una variable, el nombre de la variable es el que usamos para llamar a la función.<br />
<br />
[https://www.jasoft.org/Blog/post/Escribiendo-codigo-JavaScript-limpio-funciones-anonimas-auto-ejecutables.aspx#targetText=Los%20dos%20par%C3%A9ntesis%20finales%20se,una%20referencia%20a%20la%20misma.&targetText=La%20variable%20f2%20sin%20embargo,funci%C3%B3n%20miFuncion%20tras%20su%20ejecuci%C3%B3n. Una buena explicación la encontramos en este enlace].<br />
<br />
: '''Las funciones anónimas son extremadamente útiles porque nos permiten definir complicados patrones de programación, necesarios para construir aplicaciones profesionales. Las utilizaremos en el apartado [[Programación Asíncrona en JavaScript]].'''<br />
<br />
== Funciones estándar ==<br />
Son funciones definidas por JavaScript. Estas funciones realizan procesos que simplifican tareas complejas. Las siguientes son las que más se usan:<br />
* '''isNaN(valor)''' – Devuelve true si el valor entre paréntesis no es un número.<br />
* '''parseInt(valor)''' – Convierte una cadena de caracteres con un número en un número entero.<br />
* '''parseFloat(valor)''' – Convierte una cadena de caracteres con un número en un número decimal.<br />
* '''encodeURIComponent(valor)''' – Codifica una cadena de carateres para ser incluida en una URL.<br />
* '''decodeURIComponent(valor)''' – Decodifica una cadena de caracteres.<br />
<br />
Podemos ver un ejemplo donde se ve el funcionamiento de '''encodeURIComponen()'''.<br />
<source lang="javascript"><br />
let nombre = "Juan Pérez"<br />
let codificado = encodeURIComponent(nombre);<br />
let miURL = "http://www.ejemplo.com/contacto.html?nombre=" + codificado;<br />
console.log(miURL)<br />
//salida:http://www.ejemplo.com/contacto.html?nombre=Juan%20P%C3%A9rez<br />
</source><br />
<br />
== Recursividad ==<br />
Está perfectamente bien que una función se llame a sí misma, siempre que no lo haga con tanta frecuencia que desborde la pila. Una función que se llama a sí misma se llama recursiva. La recursividad permite escribir algunas funciones con un estilo diferente.<br />
<br />
Veamos un ejemplo con una función que devuelve la potencia de un número elevado a otro: 2<sup>5</sup> = 2 * 2 * 2 * 2 * 2 = 32<br />
* Función '''power(base, exponente)''' programada utilizando la sentencia '''for''':<br />
: <source lang="javascript"><br />
<br />
function power(base, exponente) {<br />
let result = 1;<br />
for (let cont = 0; cont < exponente; cont++) {<br />
result *= base;<br />
}<br />
return result;<br />
}<br />
<br />
</source><br />
* Función '''power(base, exponente)''' programada utilizando '''recursividad''':<br />
: <source lang="javascript"><br />
function power(base, exponente) {<br />
if (exponente == 0) {<br />
return 1;<br />
} else {<br />
return base * power(base, exponente - 1);<br />
}<br />
}<br />
</source><br />
: '''Pero, esta implementación tiene un problema pues es unas tres veces más lenta que la versión del ''for loop''. '''<br />
: Aquí aparece el dilema de la elegancia frente a la velocidad de procesamiento. Y, preocuparse sobre la eficiencia, en muchas situaciones puede ser simplemente una distracción.<br />
: Pero, la recursividad no siempre es, simplemente, una ineficiente alternativa a los bucles. Por ejemplo, podemos considerar esta situación: "Comenzando desde el número 1 y, repetidamente, sumar 5 o multiplicar por 3, se puede producir un conjunto infinito de números. ¿Cómo escribirías una función que, dado un número, intenta encontrar una secuencia de tales sumas y multiplicaciones que produzca ese número?"<br />
:: (Por ejemplo, para el número 13 = 1 * 3 + 5 + 5. Pero, para el número 15 no existe ningún modo de conseguirlo con este método).<br />
: Podemos ver una solución recursiva:<br />
:<source lang="javascript"><br />
<br />
function encontrarSolucion(objetivo) {<br />
function encontrar(actual, historial) {<br />
if (actual == objetivo) {<br />
return historial;<br />
} else if (actual > objetivo) {<br />
return null;<br />
} else {<br />
return encontrar(actual + 5, `(${historial} + 5)`) || encontrar(actual * 3, `${historial} * 3`);<br />
}<br />
}<br />
return encontrar(1, "1");<br />
}<br />
</source><br />
<br />
<br />
[[JavaScript|Volver]]</div>Vieites