Atlasingeniería

Algoritmos y programaciónFundamentosTema 4

Funciones, parámetros y alcance

Una función encapsula una transformación detrás de un contrato. Parámetros explícitos y alcance reducido vuelven visibles sus dependencias y efectos.

Para este tema conviene tener claro:Condicionales y ciclos

Una función útil no es sólo código reutilizado. Es una frontera: recibe datos, promete un resultado y esconde los pasos internos. Cuanto más claro sea ese contrato, menos necesita saber quien la llama.

La función como contrato

El nombre expresa intención; los parámetros describen entradas; el retorno comunica la salida. Las precondiciones limitan valores aceptados y las postcondiciones explican la garantía.

const rectangleArea = (width: number, height: number): number => {
  if (width < 0 || height < 0) throw new Error('Las medidas no pueden ser negativas.');
  return width * height;
};

Validar cerca de la frontera evita que estados inválidos circulen por el programa.

Antes de seguir, predecí

Pasás una lista a una función y la función le agrega un elemento. ¿Cambia la lista de afuera?

Parámetro y argumento no son lo mismo

Un parámetro es el nombre local definido por la función; un argumento es el valor entregado en una llamada. Pasar un objeto permite que dos partes observen la misma instancia. Reasignar el parámetro es local, pero mutar el objeto compartido puede afectar al llamador.

Si una función no necesita modificar la entrada, conviene que su contrato lo impida o devuelva una nueva estructura. Así los efectos no quedan escondidos detrás de una llamada inocente.

Dónde existe cada nombre

El alcance determina dónde existe un nombre. Variables locales evitan colisiones y reducen el estado que hay que considerar. Buscar datos en variables globales vuelve implícitas las dependencias y complica pruebas concurrentes o aisladas.

La regla práctica es declarar cada nombre en el alcance más chico que cubra su uso. Un dato que sólo participa en una rama no necesita vivir durante toda la función.

Escena 1 — Dos marcos con una variable del mismo nombre

paso a paso

Cargando la escena…

Las dos variables se llaman total y no tienen nada que ver: una vive en cada marco. La lista es el caso opuesto: el nombre es otro y el objeto es el mismo, así que modificarla se ve desde afuera.

El cierre: capturar el alcance de afuera

Una función interna puede capturar nombres del alcance exterior. Ese cierre mantiene acceso a los vínculos incluso después de que la función externa termina. Sirve para configurar funciones y encapsular estado privado.

También puede retener memoria o estado mutable más tiempo del esperado. Conviene capturar sólo lo necesario y hacer evidente si varias funciones comparten el mismo estado.

Por valor, por referencia y lo que se captura

const addItem = (cart: string[], item: string): void => {
  cart.push(item); // modifica el arreglo de quien llamó
};

const withItem = (cart: readonly string[], item: string): string[] => [...cart, item]; // devuelve uno nuevo

const counter = () => {
  let count = 0;             // vive mientras alguien tenga la función devuelta
  return () => (count += 1); // la clausura capturó la variable, no su valor
};

const next = counter();
next(); // 1
next(); // 2

Las dos primeras funciones hacen lo mismo y tienen contratos opuestos: una cambia lo que le pasaron y la otra no toca nada. Quien llama no puede saber cuál es cuál sin abrir el código, y por eso el nombre y el tipo tienen que decirlo: addItem suena a que modifica, withItem suena a que devuelve.

La tercera muestra lo que más confunde de las clausuras: lo que se captura es la variable, no el valor que tenía en ese momento. Por eso el contador funciona, y por eso un ciclo que crea funciones dentro de un var compartido termina con todas las funciones viendo el mismo valor final.

Qué hace buena a una función

SeñalQué suele indicarQué hacer
Más de tres o cuatro parámetroshay un concepto sin nombre adentroagrupar los que viajan juntos en un objeto
Un parámetro booleanola función hace dos cosaspartirla en dos funciones con nombres distintos
El nombre tiene «y»hace dos cosaspartirla
Devuelve distintos tipos según el casoquien llama tiene que adivinarun tipo de resultado explícito
Lee o escribe algo globalel resultado depende de lo que no se vepasarlo como parámetro
La fila del booleano es la más fácil de aplicar y la que más mejora el código que la recibe: enviarMail(usuario, true) no se entiende sin abrir la función.

Lo que preguntan sobre esto

Cierre

Una función define una frontera de conocimiento. Parámetros explícitos muestran dependencias, retornos muestran resultados y un alcance pequeño limita efectos. Dividir código sirve cuando cada parte obtiene un contrato más claro, no sólo cuando baja la cantidad de líneas.

Autoevaluación

¿Lo entendiste?

¿Cuál es la diferencia entre parámetro y argumento?
Una función recibe un objeto y lo modifica. ¿Qué conviene?
¿Dónde conviene declarar cada nombre?
¿Qué es un cierre y cuál es su costo?