La recursión es un concepto muy potente de la programación que consiste en que una función se llame a sí misma. Al principio puede resultar un poco complicado de entender, pero, una vez que comprendes los fundamentos, se convierte en una herramienta muy valiosa para resolver problemas complejos. En este tutorial vamos a explorar la recursión en JavaScript con ejemplos fáciles de entender.
La recursión se produce cuando una función se llama a sí misma, ya sea de forma directa o indirecta. Es parecida a un bucle, pero consiste en dividir un problema en subproblemas más pequeños y manejables.
Empecemos con un ejemplo sencillo: una función de cuenta atrás.
function countdown(num) {
// Base case
if (num <= 0) {
console.log('Blastoff!');
return;
}
// Recursive case
console.log(num);
countdown(num - 1);
}
// Call the function
countdown(5);
En este ejemplo:
num es menor o igual que 0, la función imprime «Blastoff!» y deja de llamarse a sí misma.num actual y se llama a sí misma con num - 1.Ahora veamos un ejemplo clásico de recursión: calcular el factorial de un número.
function factorial(n) {
// Base case
if (n === 0 || n === 1) {
return 1;
}
// Recursive case
return n * factorial(n - 1);
}
// Test the function
console.log(factorial(5)); // Output: 120
En este ejemplo:
n es 0 o 1, la función devuelve 1.n por el factorial de n - 1.Toda función recursiva debe tener al menos un caso base, una condición en la que la función deja de llamarse a sí misma. Sin un caso base, la recursión continuaría indefinidamente y provocaría un desbordamiento de pila.
El caso recursivo define cómo la función se llama a sí misma con una versión más pequeña o más sencilla del problema.
Ventajas:
Inconvenientes:
La recursión es una técnica muy valiosa que puede simplificar problemas complejos dividiéndolos en subproblemas más pequeños y manejables. Entender los casos base y los casos recursivos es fundamental para implementar soluciones recursivas eficaces en JavaScript.
Para saber más:
Llevas una pizzería y ofreces tres tipos de pizzas:
Si los clientes quieren, pueden añadir un número ilimitado de opciones extra: «ExtraSauce» por 1 $ o «ExtraToppings» por 2 $.
Tu tarea es escribir código que ayude al cliente a averiguar cuánto le cuesta.
Dado el nombre de la pizza como primer argumento y un número ilimitado de opciones añadidas, calcula el precio de la pizza en dólares.
pizzaPrice('Margherita');
// => 7
pizzaPrice('Caprese', 'ExtraSauce', 'ExtraToppings');
// => 12
pizzaPrice(
'Caprese',
'ExtraToppings',
'ExtraToppings',
'ExtraToppings',
'ExtraToppings',
);
// => 17
Se llama a tu función con un array de PizzaOrders y debe devolver el precio total del pedido en dólares.
Cada PizzaOrder tiene una propiedad pizza, el nombre de la pizza, y una propiedad extras, el array de opciones extra.
const margherita = new PizzaOrder('Margherita');
const caprese = new PizzaOrder('Caprese', 'ExtraToppings');
orderPrice([margherita, caprese]);
// => 18
Te darás cuenta de que no puedes escribir esto usando recursión, ya que una prueba con una cantidad enorme de pedidos provocará un Maximum call stack size exceeded.
No te preocupes, es algo intencionado: ¡intenta implementar esta función usando un bucle imperativo!
Tienes muchas opciones, como usar reduce o un bucle for, entre otras.
Cuando el intérprete de JavaScript ejecuta el código de JavaScript, lleva un registro de las funciones a las que ha entrado (que ha empezado a llamar) en una estructura de datos llamada «una pila». Cuando la función devuelve (termina), se elimina de la pila.
Sin embargo, esta pila tiene un tamaño limitado. El error más común es una función recursiva que nunca termina. Cada llamada se coloca en la pila, pero antes de que devuelva, se coloca otra llamada en la pila.
function kaboom() {
kaboom()
}
kaboom()
// => RangeError: Maximum call stack size exceeded
La traza de la pila de este error muestra la misma línea una y otra vez, lo cual tiene sentido, porque la función se llama a sí misma. Aunque en la mayoría de los casos no tiene una aplicación práctica real, puedes averiguar hasta qué altura puede llegar esa pila.
let calls = 0;
function kaboom() {
calls +=1 ;
kaboom()
}
kaboom()
// => RangeError: Maximum call stack size exceeded
console.log(calls)
// => a number, generally higher than 10.000
Solo hay dos soluciones viables para un error de pila de llamadas causado por una función recursiva síncrona:
Regístrate en Exercism para aprender y dominar JavaScript con 37 conceptos159 ejercicios y mentoría humana real, todo gratis.