Ver índice de contenidos del libro

2.7. Funciones

Las funciones de JavaScript no suelen definirse mediante la clase Function, sino que se crean mediante la palabra reservada function:

function suma(a, b) {
  return a+b;
}

No es obligatorio que las funciones tengan una instrucción de tipo return para devolver valores. De hecho, cuando una función no devuelve ningún valor o cuando en la instrucción return no se indica ningún valor, automáticamente se devuelve el valor undefined.

Para llamar a la función en cualquier instrucción, se indica su nombre junto con la lista de parámetros esperados:

var resultado = suma(2, 3);

Los parámetros que se pasan pueden estar definidos mediante operaciones que se evalúan antes de pasarlos a la función:

var resultado = suma(2+1, 3-4*3+4);

Como JavaScript no define tipos de variables, no es posible asegurar que los parámetros que se pasan a una función sean los del tipo adecuado para las operaciones que realiza la función.

Si a una función se le pasan más parámetros que los que ha definido, los parámetros sobrantes se ignoran. Si se pasan menos parámetros que los que ha definido la función, al resto de parámetros hasta completar el número correcto se les asigna el valor undefined.

Una función puede contener en su interior otras funciones anidadas:

function sumaCuadrados(a, b) {
  function cuadrado(x) { return x*x; }
  return cuadrado(a) + cuadrado(b);
}

La función anterior calcula la suma del cuadrado de dos números. Para ello, define en el interior de la función otra función que calcula el cuadrado del número que se le pasa. Para obtener el resultado final, la función sumaCuadrados() hace uso de la función anidada cuadrado().

Las funciones también se pueden crear mediante lo que se conoce como "function literals" y que consiste en definir la función con una expresión en la que el nombre de la función es opcional. Debido a esta última característica, también se conocen como funciones anónimas. A continuación se muestra una misma función definida mediante el método tradicional y mediante una función anónima:

function suma(a, b) {
  return a+b;
}
 
var miFuncion = function(a, b) { return a+b; }

Las funciones anónimas son ideales para los casos en los que se necesita definir funciones sencillas que sólamente se utilizan una vez y para las que no es necesario crear una función tradicional con nombre. Más adelante en el capítulo de JavaScript avanzado se muestra en detalle el uso de funciones anónimas con objetos.

Como se ha comentado, cuando una función recibe menos parámetros de los que necesita, inicializa el valor del resto de parámetros a undefined. De esta forma, puede ser necesario proteger a la aplicación frente a posibles valores incorrectos en sus parámetros. El método habitual es realizar una comprobación sencilla:

function suma(a, b) {
  if(isNaN(b)) {
    b = 0;
  }
  return a + b;
}

La función del ejemplo anterior comprueba que b sea un número para poder realizar correctamente la suma. En caso de que no lo sea (es decir, que sea null, undefined o cualquier valor válido distinto de un número) se le asigna el valor 0 para que la función pueda devolver un resultado válido.

JavaScript permite prescindir de la comprobación anterior y obtener el mismo resultado mediante el siguiente truco que hace uso del operador OR (||):

function suma(a, b) {
  b = b || 0;
  return a + b;
}

En el ejemplo anterior, si a la función no se le pasa el parámetro b, automáticamente se asigna el valor 0 a ese parámetro. El truco funciona porque el comportamiento del operador lógico OR (y también el del operador AND) es más complejo de lo que se ha explicado anteriormente.

En realidad, el operador lógico OR funciona de la siguiente manera: - Si el primer operando es true o cualquier otro valor que se puede transformar en true, se devuelve directamente el valor de ese operando. - En otro caso, se evalúa el segundo operando y se devuelve directamente su valor.

Por lo tanto:

alert(true || false);  // muestra true
alert(3 || false);     // muestra 3
alert(true || 5);      // muestra true
alert(false || true);  // muestra true
alert(false || 5);     // muestra 5
alert(3 || 5);         // muestra 3

De esta forma, si se utilizan las siguientes llamadas a la función:

suma(3);
suma(3, null);
suma(3, false);

En todos los casos anteriores la variable b vale 0. Si no se indica un parámetro, su valor es undefined, que se transforma en false y por tanto el resultado de b || 0 es 0. Si se indica null como valor del parámetro, también se transforma en false, por lo que nuevamente el resultado de b || 0 es 0. Por último, si se indica directamente el valor false al parámetro, también provoca que el resultado de b || 0 sea 0. En cualquier otro caso, el parámetro b valdrá lo mismo que se la haya pasado en la llamada a la función.

Como el número de argumentos que se pasan a una función de JavaScript puede ser variable e independiente del número de parámetros incluidos en su definición, JavaScript proporciona una variable especial que contiene todos los parámetros con los que se ha invocado a la función. Se trata de un array que se llama arguments y solamente está definido dentro de cualquier función.

function suma(a, b) {
  alert(arguments.length);
  alert(arguments[2]);
  return a + b;
}
 
suma(3, 5);

La propiedad arguments.length devuelve el número de parámetros con los que se ha llamado a la función. En el caso del ejemplo anterior, se mostraría el valor 2. Como arguments es un array, se puede acceder directamente a cualquier parámetro mediante la notación tradicional de los arrays. En este caso, el valor arguments[2] devuelve undefined, ya que la función se llama con dos parámetros y por tanto el tercer parámetro no está definido.

El array arguments permite crear funciones con un número variable de argumentos:

function mayor() {
  var elMayor = arguments[0];
  for(var i=1; i<arguments.length; i++) {
    if(arguments[i] > elMayor) {
      elMayor = arguments[i];
     }
  }
  return elMayor;
}
 
var variable1 = mayor(1, 3, 5, 8);
var variable2 = mayor(4, 6, 8, 1, 2, 3, 4, 5);

Técnicamente, arguments no es un array, sino que es un objeto de tipo Arguments. Sin embargo, por sus propiedades y sus métodos de acceso, se puede considerar como si fuera un array.

Una última propiedad del objeto arguments que no suele utilizarse habitualmente, pero que puede ser necesaria en ocasiones es la propiedad callee. La propiedad callee hace referencia a la función que se está ejecutando. En el siguiente ejemplo se utiliza la propiedad callee para mostrar el código fuente de la función que se está ejecutando:

function suma(a, b) {
  alert(arguments.callee);
  return a + b;
}
 
suma(3, 5);

La propiedad callee se puede utilizar para determinar el número de parámetros que espera la función:

function suma(a, b) {
  alert(arguments.callee.length);
  alert(arguments.length);
  return a + b;
}
 
suma(3, 5, 7, 9);

La propiedad arguments.callee.length indica el número de parámetros que se incluyen en la definición de la función, en este caso 2. Como se ha visto anteriormente, la propiedad arguments.length indica el número de parámetros con los que se ha llamado a la función, en este caso 4.