Skip to content

Funciones

En JavaScript, las funciones son bloques de código diseñados para realizar tareas específicas. Son uno de los pilares fundamentales de la programación, ya que permiten escribir código modular, reutilizable y fácil de mantener. 💡

Seguramente ya has usado funciones integradas como alert(message), prompt(message, default) o confirm(question). ¡Pero también puedes crear tus propias funciones! 🚀

Declaración de funciones

Para declarar una función, usa la palabra clave function seguida del nombre de la función, paréntesis () (que pueden contener parámetros) y un bloque de código {}:

function showMessage() {
alert("¡Hola a todos! 👋");
}

Con parámetros

Las funciones pueden aceptar parámetros, que son valores que pasan información a la función:

function showMessage(message) {
alert(message);
}

Ejecución de una función

Una vez declarada, se llama a la función escribiendo su nombre seguido de paréntesis. Si tiene parámetros, pasa los valores dentro de ellos:

showMessage("¡Hola a todos! 🎉");
showMessage("¡Hasta la próxima! 👋");

Ventaja clave: Evitas duplicar código. Si necesitas cambiar cómo funciona, ¡solo debes modificar la función! 🛠️

Parámetros por defecto ES6

A partir de ES6, puedes asignar valores predeterminados a los parámetros. Esto asegura que la función pueda funcionar incluso si no recibe ciertos argumentos:

function saludar(nombre = "usuario") {
alert(`¡Hola, ${nombre}! 🤗`);
}
saludar(); // ¡Hola, usuario!
saludar("Lucas"); // ¡Hola, Lucas!

Retorno de valores

Una función puede devolver un resultado al llamarla, usando la palabra clave return. Esto permite que otras partes del código utilicen el valor devuelto:

function sum(a, b) {
return a + b;
}
let result = sum(2, 3);
alert(result); // 5

Expresiones de función

En JavaScript, además de declarar funciones de forma clásica, puedes crear funciones usando expresiones de función. Estas son funciones anónimas asignadas a una variable.

const sayHello = function () {
alert("¡Hola desde una expresión! 🌟");
};
sayHello(); // ¡Hola desde una expresión!

Diferencia clave: Las expresiones de función no se elevan (hoisting). Debes definirlas antes de llamarlas.

Callbacks

Un callback es una función pasada como argumento a otra función y ejecutada después de completar alguna operación. Son esenciales para manejar asincronía. 💻

function greet(name, callback) {
console.log(`Hola, ${name}!`);
callback();
}
greet("Lucas", () => console.log("Adiós 👋"));

Funciones Flecha ES6

Las funciones flecha, también conocidas como arrow functions son una forma moderna, ✂️ más corta y 💡 más clara de escribir funciones en JavaScript. Su sintaxis es súper elegante y se reconocen fácilmente gracias a su característica flecha =>.

let func = (arg1, arg2, ..., argN) => expresión;

🔍 ¿Qué significa esto?

Es como decir: “Crea una función llamada func que reciba los parámetros arg1, arg2, ..., argN, evalúe la expresión a la derecha de la flecha y devuelva el resultado automáticamente”.

Es básicamente una forma abreviada de escribir:

let func = function(arg1, arg2, ..., argN) {
return expresión;
};

Un ejemplo práctico

Supongamos que queremos sumar dos números. Con una función flecha, podríamos escribir:

let sum = (a, b) => a + b;
// Es lo mismo que escribir:
// let sum = function(a, b) {
// return a + b;
// };
alert(sum(1, 2)); // 3

👀 ¿Qué está pasando aquí? (a, b) => a + b define una función que recibe dos argumentos, a y b. Luego, evalúa la expresión a + b y devuelve el resultado automáticamente. ¡Así de simple y directo!

Funciones Flecha Multilínea

Hasta ahora, hemos visto ejemplos simples que caben en una sola línea. Pero ¿qué pasa si nuestra función necesita varias líneas de código? En ese caso, podemos usar llaves {} para envolver las instrucciones y añadir un return explícito (como en las funciones tradicionales).

let sum = (a, b) => {
// Aquí abrimos una función multilínea
let result = a + b;
return result; // Necesitamos usar "return" cuando hay llaves
};
alert(sum(1, 2)); // 3

🔑 Recuerda: Si usas llaves {}, necesitas incluir un return explícito para devolver el resultado.

Scope y Closures ES6

Entender el scope y los closures es clave para escribir código eficiente y moderno en JavaScript. 🧠💻 A partir de ES6, estos conceptos se volvieron más claros gracias a la introducción de nuevas herramientas como let y const. ¡Veamos todo esto en acción! 🚀

Scope

El scope (o ámbito) se refiere al contexto donde las variables existen y son accesibles. JavaScript organiza el scope en tres tipos principales:

  • Scope Global 🌍
  • Scope Local 🏠
  • Scope de Bloque 📦 (introducido en ES6 con let y const)

🌍 Scope Global

Las variables declaradas fuera de cualquier función o bloque pertenecen al scope global. Esto significa que puedes acceder a ellas desde cualquier lugar del código.

let globalVar = "Soy una variable global";
function showGlobalVar() {
alert(globalVar);
}
showGlobalVar(); // Soy una variable global

🏠 Scope Local

Las variables declaradas dentro de una función tienen un alcance limitado a esa función. No puedes acceder a ellas desde fuera.

function myFunction() {
let localVar = "Soy una variable local";
console.log(localVar);
}
myFunction(); // Soy una variable local
console.log(localVar); // ❌ Error: localVar no está definida

📦 Scope de Bloque

A partir de ES6, puedes usar let y const para declarar variables con scope de bloque. Esto significa que solo están disponibles dentro del bloque donde se declaran.

if (true) {
let blockVar = "Soy una variable de bloque";
console.log(blockVar); // Soy una variable de bloque
}
console.log(blockVar); // ❌ Error: blockVar no está definida

⛓️ Scope Anidado

Los scopes pueden estar anidados. Una función puede acceder a las variables definidas en su scope externo.

let outerVar = "Estoy fuera";
function outerFunction() {
let innerVar = "Estoy dentro";
function innerFunction() {
console.log(outerVar); // Estoy fuera
console.log(innerVar); // Estoy dentro
}
innerFunction();
}
outerFunction();

🧩 ¿Qué aprendimos? Las funciones “heredan” variables de su scope superior, pero no al revés.

Closures

Un closure es una función que “recuerda” el entorno donde fue creada, incluyendo las variables del scope externo. Esto sucede incluso después de que la función haya terminado de ejecutarse.

function crearSaludador(nombre) {
return function () {
console.log(`¡Hola, ${nombre}!`);
};
}
const saludarLucas = crearSaludador("Lucas");
saludarLucas(); // ¡Hola, Lucas!
const saludarMaria = crearSaludador("Maria");
saludarMaria(); // ¡Hola, Maria!

📋 ¿Qué pasó aquí?

  1. Función Externa: crearSaludador toma un parámetro nombre y devuelve una nueva función.
  2. Función Interna (closure): La función devuelta “recuerda” el valor de nombre del momento en que fue creada.
  3. Ejecutar el Closure: Cada vez que llamamos a las funciones devueltas (saludarLucas, saludarMaria), estas utilizan el valor de nombre que quedó guardado en su entorno.

Ejemplo de contador

function crearContador() {
let contador = 0;
return function () {
contador++;
console.log(contador);
};
}
const contador1 = crearContador();
contador1(); // 1
contador1(); // 2
contador1(); // 3
const contador2 = crearContador();
contador2(); // 1
contador2(); // 2

¿Por qué es útil? Este patrón es ideal para guardar un estado privado en funciones, evitando conflictos con otras partes del código.

Spread y Rest Operators ES6

JavaScript tiene funciones nativas súper útiles que aceptan un número arbitrario de argumentos. ¡Veamos algunos ejemplos! 🚀

  • 🧮 Math.max(arg1, arg2, ..., argN) – Devuelve el argumento más grande.
  • 📦 Object.assign(dest, src1, ..., srcN) – Copia las propiedades de src1…N en dest.
  • …¡Y muchos más! 🎉

✨ Parámetros Rest ...

Cuando llamas a una función, puedes pasarle cualquier cantidad de argumentos, ¡y JavaScript no se quejará! 💡

Por ejemplo:

function sum(a, b) {
return a + b;
}
alert(sum(1, 2, 3, 4, 5)); // 3

⚠️ Aquí solo se toman los dos primeros argumentos. ¿Y el resto?

Usamos ... para capturar todos los argumentos restantes en un array:

function sumAll(...args) {
let sum = 0;
for (let arg of args) {
sum += arg;
}
return sum;
}
alert(sumAll(1)); // 1
alert(sumAll(1, 2)); // 3
alert(sumAll(1, 2, 3)); // 6

🎭 Un ejemplo más interesante

Podemos capturar los primeros parámetros como variables y el resto como un array

function showName(firstName, lastName, ...titles) {
alert(`${firstName} ${lastName}`); // Lucas Barbero
alert(titles[0]); // Curso JavaScript
alert(titles[1]); // 2025
alert(titles.length); // 2
}
showName("Lucas", "Barbero", "Curso JavaScript", "2025");

🌈 Operador Spread ...

Si los parámetros rest juntan argumentos en un array, el operador spread (...) hace lo contrario: ¡expande un array en una lista de argumentos! 🪄

Por ejemplo, si queremos obtener el valor máximo de un array

let numbers = [1, 5, 2, 9, 3, 7];
alert(Math.max(...numbers)); // 9

¡Incluso podemos combinarlo con valores normales o con otros arrays! 🤯

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];
alert(Math.max(0, ...arr1, 2, ...arr2, 25)); // 25

🧩 ¿Y para combinar arrays?

¡Fácil!

let merged = [0, ...arr1, 2, ...arr2];
alert(merged); // 0, 1, -2, 3, 2, 8, 3, -8

También funciona con cadenas, convirtiéndolas en arrays de caracteres:

let str = "Hola";
alert([...str]); // ['H', 'o', 'l', 'a']

🛠️ Copia de Objetos y Arrays

El operador spread es genial para crear copias. ¡Mucho más corto y limpio que Object.assign! 💡

Copia de un array

let arr = [1, 2, 3];
let arrCopy = [...arr];
alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true
alert(arr === arrCopy); // false

Copia de un objeto

let obj = { a: 1, b: 2 };
let objCopy = { ...obj };
alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true
alert(obj === objCopy); // false

¡Además, las copias son independientes! Cambiar el original no afecta la copia. 🙌