Funciones

<< Estructuras de control Colecciones de datos >>

En JavaScript, declaramos funciones usando la palabra reservada function antes del nombre de la función. Los parámetros que le pasaremos a la función van dentro del paréntesis tras el nombre de la misma. Una vez definida la función, entre las llaves declaramos el cuerpo de la misma. El nombre de las funciones (como el de las variables) se suele escribir en formato camelCase con la primera letra en minúsculas.

Para ejecutar la función basta con poner el nombre de la misma en el código pasándole los valores de cada parámetro entre los paréntesis. Aunque no reciba ningún valor, los paréntesis son obligatorios en la llamada.

function sayHello(name) {
    console.log("Hello " + name);
}

sayHello("Tom"); // "Hello Tom"

No necesitas tener la función declarada antes de la llamada, esto es debido a que el motor de ejecución de JavaScript hace 2 pasadas. Primero procesa las declaraciones de variables y funciones, y después ejecuta el programa.

Podemos llamar a una función enviándole más o menos parámetros de los establecidos en la declaración. Si le enviamos más parámetros, los sobrantes serán ignorados y si le enviamos menos, a los no recibidos se les asignará el valor undefined.

function sayHello(name) {
  console.log("Hello " + name);
}

sayHello(); // "Hello undefined"

Retorno de valores

Podemos usar la palabra reservada return para devolver un valor en una función. Si intentamos acceder al valor de una función que no devuelve nada, obtendremos undefined.

function totalPrice(priceUnit, units) {
    return priceUnit * units;
}

let total = totalPrice(5.95, 6);
console.log(total);  // 35.7

Es conveniente recordar que en cuanto se ejecuta la instrucción return, la función termina inmediatamente devolviendo el valor correspondiente. No tiene sentido tener instrucciones de código después de la instrucción return, a no ser que haya una estructura condicional que discrimine entre varias opciones a la hora de devolver un valor.

Funciones anónimas

La forma de declarar una función anónima es no asignarle ningún nombre. Podemos asignar dicha función como valor a una variable, ya que es un tipo de valor (como puede ser un string o número), por tanto, puede ser asignada a (o referenciada desde) múltiples variables. Se utiliza igual que una función clásica.

let totalPrice = function(priceUnit, units) {
    return priceUnit * units;
}

console.log(typeof totalPrice); // "function" (tipo de datos del identificador totalPrice)

console.log(totalPrice(5.95, 6)); // 35.7
let getTotal = totalPrice; // Podemos crear varios identificadores que referencien a la misma función
console.log(getTotal(5.95, 6));  // 35.7

Funciones flecha (o lambda)

Una de las funcionalidades más importantes que se añadió en ES2015 fue la posibilidad de usar las funciones lambda (o flecha). Otros lenguajes como C#, Java, etc. también las soportan. Estas expresiones ofrecen la posibilidad de crear funciones anónimas pero con algunas ventajas.

Vamos a ver las diferencias que tiene por creando dos funciones equivalentes (una anónima y otra lambda que hacen lo mismo):

let sum = function(num1, num2) {
    return num1 + num2;
}
console.log(sum(12,5)); // 17

let sum = (num1, num2) => num1 + num2;
console.log(sum(12,5)); // 17

Cuando declaramos una función flecha o lambda, la palabra reservada function no se usa. Si sólo se recibe un parámetro, los paréntesis pueden ser omitidos. Después de los parámetros debe ir una flecha (=>), y el contenido de la función.

let square = num => num * num;
console.log(square(3)); // 9

Si sólo hay una instrucción dentro de la función flecha, podemos omitir las llaves '{}'. En este caso debemos omitir la palabra reservada return ya que lo hace de forma implícita (devuelve el resultado de esa instrucción). Si hay más de una instrucción, usamos las llaves y se comporta como una función normal, y por tanto si devuelve algo, debemos usar la palabra reservada return.

let sumInterest = (price, percentage) => {
    let interest = price * percentage / 100;
    return price + interest;
}
console.log(sumInterest(200,15)); // 230

La diferencia más importante entre ambos tipos de funciones es el comportamiento de la palabra reservada this. Pero eso lo veremos en el bloque de Programación orientada a objetos.

Parámetros por defecto

Si un parámetro se declara en una función y no se le pasa un valor cuando la llamamos, se establece su valor como undefined.

function sayHello(name) {
    console.log("Hello! I'm " + name);
}

sayHello(); // Prints "Hello! I'm undefined"

Una solución usada para establecer un valor por defecto era usar el operador '||' (or), de forma que si se evalúa como undefined (equivale a false), se le asigna otro valor por defecto.

function sayHello(name) {
    name = name || "Anonymous";
    console.log("Hello! I'm " + name);
}

Desde ES2015 tenemos la opción de establecer un valor por defecto directamente.

function sayHello(name = "Anonymous") {
    console.log("Hello! I'm " + name);
}

sayHello(); // "Hello! I'm Anonymous"

También podemos asignarle un valor por defecto basado en una expresión.

function getTotalPrice(price, tax = price * 0.07) {
    return price + tax;
}

console.log(getTotalPrice(100)); // 107

Ámbito de las variables

Variables globales

Cuando se declara una variable en el bloque principal (fuera de cualquier función), ésta es creada como global. Las variables que no son declaradas con la palabra reservada let son también globales (a menos que estemos usando el strict mode, que no permite hacer esto).

A una variable global podremos acceder desde cualquier parte del código. Esto es peligroso desde el punto de vista de prevenir efectos colaterales cuando se modifica su valor, por lo que se recomienda evitar este tipo de variables cuando no sea estrictamente necesario.

let global = "Hello";

function changeGlobal() {
    global = "GoodBye";
}

changeGlobal();
console.log(global); // "GoodBye"

Si olvidamos poner la palabra let al declarar una variable dentro de una función, Si no usas strict mode (Es recomendable que lo uses), se creará una variable global. En el modo estricto no te permitirá hacer eso.

'use strict';

function changeGlobal() {
    global = "GoodBye";
}

changeGlobal(); // Error → Uncaught ReferenceError: global is not defined

Variables locales

Todas las variables que se declaran dentro de una función u otro tipo de bloque (if, while, ...) son locales a dicho bloque. Es decir, solo pueden ser accedidas desde el bloque donde son declaradas (incluyendo otros bloques que estén dentro del mismo), pero no desde fuera.

function setPerson() {
    let  person = "Peter"; // Variable local
}

setPerson();
console.log(person); // Error → Uncaught ReferenceError: person is not defined

Si una variable global con el mismo nombre existe, la variable local no actualizará el valor de la variable global.

function setPerson() {
    let person = "Peter";
}

let person = "John";
setPerson();
console.log(person); // Imprime John

<< Estructuras de control Colecciones de datos >>