Funciones en JavaScript: ámbito y cierres

Aprende a organizar código JavaScript en funciones reutilizables. Escribe declaraciones de función, expresiones de función y funciones flecha; pasa valores mediante parámetros, valores predeterminados y parámetros de resto; y devuelve resultados con return. Predice dónde se puede usar una variable con los ámbitos de bloque, de función y global, usa cierres para dar a las funciones su propia memoria y pasa funciones a otras funciones como funciones de devolución de llamada para escribir código flexible de orden superior.

PrincipianteUnidad 3 de 9 del curso Curso de Programación en JavaScript

Lo que aprenderás

  1. Organiza una parte reutilizable de código como función, llámala con argumentos y elige entre una declaración de función, una expresión de función y una función flecha.
    • Escribe una declaración de función y llama a la función
      Define una función con nombre mediante la palabra clave function, llámala y explica por qué las funciones hacen que el código sea más corto, claro y fácil de modificar.
    • Almacena una función en una variable con una expresión de función
      Trata las funciones como valores: crea una expresión de función, asígnala a una variable y explica en qué se diferencia de una declaración en cuanto a elevación y nombre.
    • Escribe funciones flecha
      Usa la sintaxis abreviada de flecha, identifica cuándo una función flecha devuelve un valor automáticamente y explica en qué se diferencia de las funciones escritas con function.
  2. Diseña qué entra en una función y qué sale de ella: relaciona argumentos con parámetros, establece valores predeterminados, acepta cualquier número de argumentos, devuelve resultados y sigue cómo se ejecutan las llamadas anidadas.
    • Relaciona los argumentos con los parámetros
      Explica cómo llegan los valores de una llamada a los parámetros de la función, qué ocurre cuando hay pocos o demasiados argumentos y qué datos de quien llama puede modificar una función.
    • Establece valores predeterminados y acepta cualquier número de argumentos
      Asigna valores predeterminados a los parámetros, recopila cualquier número de argumentos con un parámetro de resto y expande un array en argumentos separados.
    • Devuelve resultados desde una función
      Devuelve un valor con return, usa el resultado en código posterior y distingue entre devolver un valor, mostrarlo o cambiar algo fuera de la función.
    • Sigue las llamadas a funciones en la pila de llamadas
      Sigue el orden en que se ejecutan y terminan las llamadas anidadas y escribe una función recursiva sencilla con un caso base.
  3. Predice dónde es visible una variable aplicando las reglas de los ámbitos de bloque, de función y global y de las funciones escritas dentro de otras funciones.
    • Distingue los ámbitos de bloque, de función y global
      Explica el ámbito de una variable declarada con let, const o var y usa variables locales para mantener las funciones independientes entre sí.
    • Predice a qué variable se refiere un nombre
      Sigue la cadena de ámbitos para encontrar la variable detrás de un nombre, reconoce el sombreado de variables y explica la elevación de declaraciones y la zona muerta temporal.
  4. Explica cómo una función conserva el acceso a las variables que la rodean después de que termine la función externa y usa esa propiedad para crear fábricas de funciones y mantener estado privado.
    • Explica qué recuerda un cierre
      Describe cómo una función conserva el acceso a las variables del ámbito en que se creó, incluso después de que la función externa haya terminado.
    • Usa cierres para crear fábricas de funciones y mantener estado privado
      Construye fábricas de funciones, mantén datos privados detrás de funciones y evita el error clásico de cierre en un bucle.
  5. Usa funciones como valores: pásalas a otras funciones como funciones de devolución de llamada, usa y escribe funciones de orden superior y construye funciones nuevas a partir de otras existentes.
    • Pasa una función de devolución de llamada a una función
      Pasa una función a otra como argumento, escribe funciones que llamen a una función de devolución de llamada y pasa la propia función en lugar de su resultado.
    • Usa y escribe funciones de orden superior
      Reconoce funciones de orden superior, usa los métodos de array que reciben funciones de devolución de llamada y escribe tu propia función que reciba una función como entrada.
    • Construye nuevas funciones a partir de otras existentes
      Escribe funciones de orden superior que envuelvan, combinen o completen de antemano otras funciones, usando cierres para recordar la función que recibieron.

Guía de estudio de Funciones en JavaScript

5 capítulos

1

Define y llama a funciones de tres formas

Las funciones convierten instrucciones repetidas en tareas con nombre. Leerás y escribirás tres formas habituales y después decidirás si una línea crea una función, la almacena o la llama. Los pequeños cambios de sintaxis importan: una declaración está disponible antes, mientras que una expresión almacenada debe inicializarse primero, y el cuerpo de una función flecha puede cambiar si se devuelve un resultado. Estas distinciones te preparan para pasar funciones como valores ordinarios.

1.1 Escribe una declaración de función y llama a la función

Una función da nombre a una tarea y almacena las instrucciones para realizarla. Definirla no ejecuta esas instrucciones. Una llamada las ejecuta y otra llamada las ejecuta de nuevo con entradas nuevas.

Escribe la definición

Una declaración tiene la palabra clave function, un nombre, paréntesis para los parámetros y llaves para el cuerpo:

function greet(name) {
  console.log("Hello, " + name + "!");
}

Aquí name es un parámetro: un nombre local para la entrada que proporciona cada llamada. El cuerpo une esa entrada al texto que la rodea y muestra el resultado. La llave de cierre marca el final de la definición; la ejecución continúa con la siguiente sentencia fuera de ella.

Una función sin entradas también necesita paréntesis. Por ejemplo, function sayHi() { console.log("Hi"); } define una tarea con una lista de parámetros vacía. Las llaves pertenecen a la definición; los paréntesis después de un nombre aparecen tanto en las definiciones como en las llamadas, con funciones distintas.

Ejecuta la tarea
greet("Amira");
greet("Li");

La primera llamada asigna a name el valor "Amira" y muestra «Hello, Amira!». La segunda inicia una nueva llamada con name igual a "Li" y muestra «Hello, Li!». La definición se comparte; la entrada pertenece a cada llamada individual.

greet por sí solo se refiere al valor de la función. No ejecuta el cuerpo. Esta distinción importa cuando una línea parece no hacer nada: sayHi; lee un valor de función y lo descarta, mientras que sayHi(); muestra «Hi».

Sustituye instrucciones copiadas

Supón que varios informes necesitan un encabezado rodeado de líneas:

function printHeading(title) {
  console.log("-----");
  console.log(title);
  console.log("-----");
}

printHeading("Report");
printHeading("Totals");

La primera llamada muestra una línea, «Report» y otra línea. La segunda muestra el mismo marco alrededor de «Totals». Para cambiar el estilo de las líneas, edita las dos sentencias que las muestran en esta única definición. Sin la función, habría que corregir cada encabezado copiado por separado.

Elige un nombre que indique qué hace una llamada. printHeading describe una acción; isValidEmail nombra una comprobación de sí o no. Usa camelCase, con la primera palabra en minúscula y las siguientes con mayúscula inicial. Si un nombre propuesto une dos tareas distintas con «y», considera dar a cada tarea su propia función.

Lee código que llama anticipadamente a una declaración

Las declaraciones se preparan antes de que se ejecute el código que las rodea. Este comportamiento se llama elevación de declaraciones (hoisting):

sayHi();
function sayHi() {
  console.log("Hi");
}

La llamada funciona dentro del ámbito de la declaración aunque la definición escrita aparezca después. La elevación no hace que el cuerpo se ejecute antes; hace que la función esté disponible para llamarla.

Comprueba la ortografía y el uso de mayúsculas cuando falle una llamada. Greet() y greet() son nombres diferentes. Llamar a greeet() sin declararla genera un ReferenceError; omitir los paréntesis de llamada puede fallar silenciosamente, porque leer una función existente es código válido.

Puntos clave

  • Definir una función almacena instrucciones; llamarla las ejecuta.
  • Llama con paréntesis, incluso cuando no hay argumentos.
  • Una declaración está disponible antes de su posición escrita dentro del mismo ámbito.
  • Da nombre a una tarea clara para que el código repetido tenga un solo lugar donde modificarse.

1.2 Almacena una función en una variable con una expresión de función

Las funciones son valores. Puedes guardar una en una variable, copiar su referencia, pasarla a otra función o devolverla. Una expresión de función crea ese valor donde se espera una expresión.

Almacena una función
const square = function (n) {
  return n * n;
};

const answer = square(4);

La expresión después de = crea una función. La asignación la almacena en square; la llamada posterior devuelve 16. Esta sentencia termina con punto y coma, siguiendo la convención de formato usada aquí.

La posición de function distingue las formas. Una definición escrita como function square(n) { ... } por sí sola es una declaración. Una función escrita después de = o directamente como argumento de una llamada es una expresión. Ambas formas de función ordinaria pueden aceptar parámetros y devolver valores.

Usa const para una variable que contiene una función cuando su valor deba mantenerse igual. Se permite llamar a square(5); asignar square = 5; genera un TypeError. La constante protege la variable frente a su sustitución. No impide llamar repetidamente a la función.

Guarda una función o guarda su resultado
const sq = square;
const result = square(3);

sq se refiere a la misma función que square. Llamar a sq(3) devuelve 9. result contiene el número 9 que devolvió una llamada. No se puede llamar a ese número como función. typeof square y typeof sq son "function"; typeof result es "number".

Leer una asignación de derecha a izquierda ayuda: decide primero si su lado derecho crea una función, se refiere a una función existente o llama a una. La variable de la izquierda recibe ese valor. Copiar la referencia no crea una segunda implementación independiente.

Espera a que se ejecute la asignación

Una declaración y una expresión almacenada se pueden llamar en momentos diferentes:

FormaAntes de la definición o asignación escrita
function square(n) { return n * n; }Se puede llamar dentro de su ámbito
const square = function (n) { return n * n; };Leer square genera un ReferenceError
var square = function (n) { return n * n; };square es undefined; llamarla genera un TypeError

Con const o let, el nombre no se puede usar antes de la inicialización. Con var, el nombre existe desde antes, pero el valor de función no se asigna hasta que la ejecución llega a la expresión. Elevar la variable no eleva la asignación.

Da a una expresión un nombre interno
const factorial = function fact(n) {
  return n <= 1 ? 1 : n * fact(n - 1);
};

El nombre externo es factorial. El nombre fact pertenece al interior de la función y permite que se llame a sí misma; el código externo no puede usar directamente ese nombre interno. El nombre de la expresión también puede facilitar la lectura de las trazas de la pila. Por ejemplo, factorial(3) calcula 3 por 2 por 1 y devuelve 6.

Las declaraciones funcionan bien para las principales tareas con nombre de un script. Las expresiones encajan donde el código necesita un valor de función, como en una asignación a una variable o en un argumento. Elegir una expresión cambia cómo se crea y almacena el valor, no cómo lo llaman los paréntesis.

Puntos clave

  • Una expresión de función crea un valor de función dentro de otra expresión.
  • Asignar square copia una referencia a la función; asignar square(3) almacena su resultado.
  • Una expresión de función almacenada en const solo se puede llamar después de su inicialización.
  • Una variable de función declarada con var contiene undefined antes de que se ejecute su asignación.
  • Una expresión con nombre puede usar su nombre interno para llamarse a sí misma.

1.3 Escribe funciones flecha

Las funciones flecha son expresiones de función con una escritura más corta. Su comportamiento de retorno depende de lo que sigue a la flecha, así que examina el cuerpo antes de decidir qué produce una llamada.

Elige la forma de los parámetros
const sayHi = () => "hi";
const double = n => n * 2;
const add = (a, b) => a + b;

Si no hay parámetros, se necesitan paréntesis vacíos. Un solo parámetro simple puede omitirlos. Dos o más los requieren. Un parámetro predeterminado o de resto también necesita paréntesis: (n = 1) => n * 2 y (...nums) => nums.length son válidos.

La flecha separa las entradas del cuerpo. const double = n => n * 2; crea la función y la almacena; double(6) la llama después y devuelve 12. Como cualquier const que contiene una expresión de función, double no se puede leer antes de que se ejecute su línea de inicialización.

Devuelve una expresión o escribe un bloque
CuerpoEjemploResultado de la llamada con 2 y 3
Expresión concisa(a, b) => a + b5
Bloque con return(a, b) => { return a + b; }5
Bloque sin return(a, b) => { a + b; }undefined

Un cuerpo conciso devuelve su expresión automáticamente. Las llaves comienzan un bloque de sentencias. En un bloque, evaluar una expresión no la devuelve a quien llamó; escribe return de forma explícita.

Usa un bloque cuando la tarea necesite trabajo intermedio:

const describe = (n) => {
  const kind = n % 2 === 0 ? "even" : "odd";
  return n + " is " + kind;
};

Para describe(7), la condición es falsa, por lo que kind toma el valor "odd". El retorno une entonces el número y las palabras en «7 is odd». Eliminar ese retorno mantendría el cálculo local, pero daría undefined a quien llamó.

Devuelve un literal de objeto

Un literal de objeto también usa llaves. Enciérralo entre paréntesis para que el analizador lo interprete como una expresión:

const makePoint = (x, y) => ({ x: x, y: y });

makePoint(2, 5) devuelve un objeto con x igual a 2 e y igual a 5. Sin los paréntesis, la primera llave comienza un bloque. La forma con una sola propiedad () => { value: 1 } devuelve undefined; la forma similar con dos propiedades separadas por una coma produce un error de sintaxis. Los paréntesis cambian cómo se interpreta el cuerpo.

Conoce los límites de la forma abreviada

Las funciones flecha no tienen sus propios this ni arguments, y no se puede llamar a ellas con new para construir objetos. Para un cálculo sencillo que no usa ni this ni arguments, una función flecha y una expresión de función ordinaria se comportan igual. Sustituir todas las funciones ordinarias por funciones flecha puede cambiar el código que depende de esas características.

Las funciones flecha cortas son especialmente legibles como funciones de devolución de llamada. [1, 2, 3].map(n => n * 10) pasa una función que devuelve un elemento transformado y produce [10, 20, 30]. Cambiarla a n => { n * 10; } hace que se pierda silenciosamente cada valor devuelto.

Puntos clave

  • Un cuerpo conciso de función flecha devuelve su expresión automáticamente.
  • Un cuerpo de bloque de función flecha necesita un return explícito para devolver un valor calculado.
  • Usa paréntesis alrededor de un literal de objeto devuelto por una función flecha concisa.
  • Las listas vacías, con varios parámetros, con parámetros predeterminados y con parámetros de resto necesitan paréntesis.
  • Las funciones flecha no tienen sus propios this ni arguments y no pueden ser constructores.
2

Pasa valores a funciones y obtén resultados

Una llamada a función tiene una parte de entrada y otra de salida. Relaciona argumentos con parámetros, maneja entradas opcionales o flexibles y sigue el valor devuelto a quien llamó. También distinguirás los cambios locales de los cambios en un array compartido y seguirás las llamadas anidadas mientras su trabajo se pausa y se reanuda. El mismo modelo de llamada y retorno explica la recursión sencilla, en la que varias llamadas de una función esperan a que terminen otras llamadas más pequeñas.

2.1 Relaciona los argumentos con los parámetros

Los parámetros de una función dan nombre a los valores proporcionados por una llamada. Para seguir una llamada, relaciona primero las entradas por posición y después sigue las operaciones del cuerpo.

Relaciona posiciones y tipos
function area(width, height) {
  return width * height;
}

area(4, 2.5);

width y height son parámetros; 4 y 2,5 son argumentos. Durante esta llamada, width contiene 4 y height contiene 2,5, por lo que el resultado es 10. Los nombres de los parámetros no se relacionan con los nombres de las variables de quien llama. Con divide(a, b), cambiar divide(10, 2) por divide(2, 10) cambia el resultado de 5 a 0,2.

JavaScript no exige un número concreto de argumentos. area(4) deja height como undefined; multiplicar por ese valor produce NaN. area(4, 2, 99) devuelve 8 porque este cuerpo no usa el tercer argumento. Una función puede recopilar argumentos adicionales, pero los que no se usan no causan un error automático.

Los tipos también importan aunque se acepte la llamada. area("4", 2) devuelve 8 porque la multiplicación convierte el texto. Una función de suma se comporta de otra manera: add("4", 2) devuelve «42» cuando su cuerpo es return a + b;. Si el texto representa un número, add(Number("4"), 2) devuelve 6.

Reasigna un parámetro local

Cada parámetro es local a su llamada. Asignarle un número nuevo no reasigna la variable de quien llama:

let score = 5;
function reset(s) {
  s = 0;
}
reset(score);

La llamada copia el valor 5 en s. La asignación cambia s a 0 y score sigue valiendo 5. Los números, las cadenas y los booleanos siguen esta regla de copia de valores. El código externo no puede leer s directamente; una función anidada puede conservar el acceso a él mediante un cierre.

Modifica un array mediante una referencia copiada

Un valor de tipo array es una referencia a un array. Al pasar ese valor se copia la referencia, por lo que quien llama y el parámetro pueden acceder al mismo array:

const list = [1, 2];
function addItem(arr) {
  arr.push(3);
}
addItem(list);

Ahora list es [1, 2, 3]. La función no reasignó list; modificó el array al que acceden ambos nombres. Una declaración const impide sustituir la referencia almacenada, no cambiar el contenido del array.

Compara con una reasignación local:

function clearLocal(arr) {
  arr = [];
}
clearLocal(list);

Esto hace que solo arr apunte a un array vacío nuevo. list sigue apuntando a [1, 2, 3]. Pregúntate si una operación modifica un array existente, como hace push, o da a un nombre un valor diferente, como hace =.

Devuelve un array nuevo cuando la entrada deba permanecer intacta
function withItem(arr, item) {
  return arr.concat(item);
}

withItem([1, 2], 3) produce [1, 2, 3] como un array nuevo. El array de entrada sigue siendo [1, 2]. Esto hace que la función sea útil cuando quien llama necesita tanto la lista original como la ampliada. Documenta mediante el nombre y el comportamiento de una función los cambios que se espera que haga en sus entradas, para que quienes la llamen puedan usarla de forma predecible.

Puntos clave

  • Los argumentos se relacionan con los parámetros por posición.
  • Un argumento ausente proporciona undefined; se permiten argumentos adicionales sin usar.
  • Reasignar un parámetro no reasigna la variable de quien llama.
  • Modificar un array mediante un parámetro cambia el array compartido.
  • Devolver un array nuevo puede preservar la entrada.

2.2 Establece valores predeterminados y acepta cualquier número de argumentos

Los valores predeterminados hacen que una entrada sea opcional; los parámetros de resto permiten que una llamada proporcione muchas entradas. La sintaxis de propagación conecta un array existente con una función que espera argumentos separados.

Aplica un valor predeterminado solo para undefined
function greet(name = "friend") {
  return "Hello, " + name;
}

Tanto greet() como greet(undefined) devuelven «Hello, friend». greet(null) devuelve «Hello, null» y greet("") devuelve «Hello, ». Un valor predeterminado se aplica a undefined, no a todos los valores que parecen vacíos.

Los valores predeterminados se evalúan cuando una llamada los necesita. Pueden usar parámetros anteriores: function makeBox(width, height = width) { return width * height; } devuelve 9 para makeBox(3) y 12 para makeBox(3, 4). El segundo argumento explícito sustituye el valor predeterminado para esa llamada.

Pon primero las entradas obligatorias. Con function total(amount, rate = 0.25) { return amount + amount * rate; }, total(80) devuelve 100 y total(80, 0.5) devuelve 120. Invertir los parámetros haría que la llamada habitual con la tasa predeterminada requiriera total(undefined, 80).

El código antiguo puede usar level = level || 50;. Esto también sustituye 0, false y una cadena vacía porque son valores falsos en contexto booleano. Un parámetro predeterminado conserva esos valores: function setVolume(level = 50) { return level; } devuelve 0 para setVolume(0) y 50 para setVolume(undefined).

Reúne argumentos con un parámetro de resto
function sum(...numbers) {
  let total = 0;
  for (const n of numbers) {
    total += n;
  }
  return total;
}

sum(1, 2, 3) coloca [1, 2, 3] en numbers y devuelve 6. sum() le da un array vacío, por lo que el bucle no suma nada y devuelve 0. Un parámetro de resto es un array real, listo para usar métodos de array o recorrerlo.

Una entrada fija puede aparecer antes del parámetro de resto: en function log(label, ...values) { console.log(label, values); }, log("scores", 7, 9) da a label la cadena «scores» y a values el array [7, 9]. Solo se permite un parámetro de resto y debe ir al final; de lo contrario, JavaScript no puede asignar los argumentos restantes sin ambigüedad con esta sintaxis.

Expande argumentos con propagación
Ubicación de ...FunciónEjemplo
Lista de parámetros de una definiciónReunir los argumentos restantesfunction sum(...numbers) { ... }
Lista de argumentos de una llamadaExpandir los elementos de un arraysum(...values)

Math.max(...[3, 7, 2]) recibe tres números y devuelve 7. Math.max([3, 7, 2]) recibe un array y devuelve NaN. Los tres puntos son idénticos en el texto, pero la sintaxis que los rodea indica qué función cumplen.

Las funciones ordinarias también tienen un objeto arguments que contiene los argumentos que se les pasaron. Es similar a un array, con entradas indexadas y una longitud, pero no es un array real y no tiene métodos propios map ni filter. Las funciones flecha no tienen su propio arguments. Para código nuevo que necesita una lista flexible de entradas, prefiere un parámetro de resto.

Puntos clave

  • Los valores predeterminados se aplican a argumentos ausentes y a undefined explícito, y conservan 0 y null.
  • Una expresión predeterminada se evalúa en cada llamada que la necesita.
  • Un parámetro de resto reúne los argumentos restantes en un array y va al final.
  • La propagación expande un array en argumentos de llamada separados.
  • El antiguo objeto arguments es similar a un array; un parámetro de resto produce un array real.

2.3 Devuelve resultados desde una función

Un valor devuelto es la salida que otro código recibe de una llamada. Mostrarlo puede enseñar el mismo valor en pantalla, pero da a quien llama un resultado diferente a menos que la función también lo devuelva.

Usa la llamada como un valor
function double(n) {
  return n * 2;
}
const x = double(5) + 1;

double(5) devuelve 10, por lo que la asignación se evalúa como 10 más 1 y almacena 11. Una llamada puede aparecer en cualquier lugar donde se necesite un valor adecuado. double(double(3)) obtiene primero 6 de la llamada interna y después devuelve 12 desde la externa. Math.round(double(2.3)) duplica el valor hasta 4,6 y lo redondea a 5.

return también termina inmediatamente la llamada actual. Una cláusula de guarda maneja un caso especial antes del trabajo principal:

function safeDivide(a, b) {
  if (b === 0) {
    return null;
  }
  return a / b;
}

safeDivide(6, 0) devuelve null y nunca llega a la división. safeDivide(6, 2) omite la cláusula de guarda y devuelve 3. Coloca la condición antes de la operación que protege.

Distingue el resultado de su visualización
function addLog(a, b) {
  console.log(a + b);
}

addLog(2, 3) muestra 5, pero su valor de retorno es undefined. Por tanto, addLog(2, 3) * 2 muestra 5 y se evalúa como NaN. Una función que llega a su final sin un retorno, o ejecuta un return; sin valor, devuelve undefined. La visualización en la consola es un efecto secundario, no el resultado numérico utilizable de la llamada.

Si quien llama necesita una suma, escribe return a + b;. Entonces podrá elegir entre mostrarla, almacenarla o usarla en otro cálculo. Así las decisiones de visualización quedan fuera de un cálculo reutilizable.

Mantén la expresión devuelta en la misma línea
function brokenAdd(a, b) {
  return
  a + b;
}

JavaScript termina la sentencia return en el salto de línea. La función devuelve undefined; nunca se llega a la expresión posterior. Para una expresión larga, empieza a escribirla o abre un paréntesis en la línea de return y después continúa debajo.

Agrupa varios resultados en un valor

Una llamada devuelve un valor, pero ese valor puede ser un array:

function minMax(nums) {
  return [Math.min(...nums), Math.max(...nums)];
}
const [low, high] = minMax([4, 9, 1]);

El array devuelto es [1, 9]. La desestructuración asigna su primera entrada a low y la segunda a high. Sigue habiendo un solo valor devuelto, que contiene dos resultados útiles.

Una función pura calcula su salida a partir de sus argumentos y no cambia nada fuera de sí misma. double es pura. Mostrar valores, actualizar una variable externa y modificar un array de entrada son efectos secundarios. Los cálculos puros son fáciles de comprobar con ejemplos de entradas y salidas; los efectos secundarios pertenecen a funciones con nombres claros allí donde el programa necesita cambios visibles.

Puntos clave

  • return proporciona el valor de la llamada y termina la llamada actual.
  • Mostrar un valor sin devolverlo deja el valor de retorno de la función en undefined.
  • Empieza la expresión devuelta en la línea de return.
  • Un array devuelto puede contener varios resultados.
  • Las funciones puras dependen de sus argumentos y no hacen cambios externos.

2.4 Sigue las llamadas a funciones en la pila de llamadas

Cuando una función llama a otra, la función que llama se pausa hasta que termina esa llamada. La pila de llamadas registra el trabajo pendiente para que la ejecución pueda reanudarse en el lugar correcto.

Añade y elimina marcos de llamadas

Cada llamada activa tiene un marco de pila que contiene sus parámetros, variables locales y lugar de retorno. Una nueva llamada se coloca en la cima de la pila; un retorno elimina ese marco superior.

function square(n) {
  return n * n;
}
function sumOfSquares(a, b) {
  return square(a) + square(b);
}
sumOfSquares(3, 4);

Primero, sumOfSquares comienza con a igual a 3 y b igual a 4. Llama a square(3), que devuelve 9 y termina. Después se ejecuta square(4) y devuelve 16. La suma pausada ahora puede completarse como 9 más 16, y sumOfSquares devuelve 25. Las dos llamadas a square no se solapan en este seguimiento.

Cada llamada obtiene parámetros y variables locales nuevos. Llamar dos veces a la misma función no reutiliza el estado numérico local de una llamada anterior. Incluso cuando una función se llama a sí misma, la nueva llamada tiene su propio marco.

Reduce un problema con recursión

Una función recursiva se llama a sí misma. Un caso base termina sin otra llamada a sí misma; un caso recursivo da un paso hacia ese caso base.

function factorial(n) {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

Para entradas enteras no negativas, esto multiplica los enteros hasta llegar a 1. Sigue factorial(4) en dos direcciones:

  1. factorial(4) espera a factorial(3).
  2. Esa llamada espera a factorial(2).
  3. Esa llamada espera a factorial(1).
  4. El caso base devuelve 1.
  5. Las llamadas en espera devuelven 2, después 6 y después 24.

La multiplicación en la llamada con n igual a 4 ocurre después de que termine la llamada más pequeña. Su propia n se ha mantenido en 4 mientras esperaba.

El caso base debe ser alcanzable. Usar solo n === 1 falla para una entrada inicial de 0 si cada llamada recursiva resta 1: los valores se vuelven negativos y nunca llegan a 1. n <= 1 cubre tanto 0 como 1. Sin una vía de parada, las llamadas repetidas agotan la pila. Chrome y Node.js muestran «RangeError: Maximum call stack size exceeded»; Firefox usa «InternalError: too much recursion».

Reconoce una versión más pequeña de la misma tarea
function countItems(list) {
  let count = 0;
  for (const item of list) {
    if (Array.isArray(item)) {
      count += countItems(item);
    } else {
      count += 1;
    }
  }
  return count;
}

countItems([1, [2, 3], [4, [5]]]) devuelve 5. Cada array anidado plantea la misma pregunta de recuento sobre una lista más pequeña. Un bucle también es adecuado para un factorial sencillo; la recursión es especialmente útil cuando los propios datos están anidados.

Si falla una llamada, lee la traza de la pila desde la llamada más reciente, arriba. Las entradas siguientes muestran qué llamadas pendientes condujeron hasta ella. Las entradas repetidas de una función pueden revelar una recursión que no se detuvo.

Puntos clave

  • La pila de llamadas registra las llamadas pendientes; los retornos eliminan el marco más reciente.
  • Cada invocación tiene sus propios parámetros y variables locales.
  • La recursión necesita un caso de parada y avanzar hacia él.
  • Los resultados recursivos vuelven a través de las llamadas en espera en orden inverso.
  • Una traza de la pila muestra la llamada que falló y las llamadas que condujeron a ella.
  • Los datos anidados pueden contener versiones más pequeñas de la misma tarea.
3

Explica dónde se puede usar una variable

Los nombres de las variables tienen significado dentro de ámbitos. Los límites de los bloques y las funciones, y el lugar donde se define una función, determinan a qué declaraciones puede acceder. Seguirás esos límites para predecir un valor o un error y después distinguirás el sombreado de variables de la actualización de una variable externa. La elevación de declaraciones y la zona muerta temporal explican por qué un nombre puede estar registrado antes de que la ejecución llegue a su línea y, aun así, no estar disponible para su uso.

3.1 Distingue los ámbitos de bloque, de función y global

El ámbito de una variable es la región donde se puede usar su nombre. El ámbito permite que las funciones mantengan separados sus datos de trabajo y, al mismo tiempo, usen entradas y valores del código que las rodea.

Delimita las declaraciones

let y const tienen ámbito de bloque. Un bloque es una región dentro de llaves, como el cuerpo de un if, de un bucle o de una función:

if (true) {
  const msg = "hi";
  console.log(msg);
}

La instrucción que muestra el valor funciona dentro del bloque. Añadir console.log(msg); después del bloque genera un ReferenceError porque ese código externo no puede acceder a esta declaración. Otra declaración externa con el mismo nombre sería una variable diferente.

Los parámetros y las variables dentro de una función son locales a esa función. En function f() { let temp = 1; }, el código externo no puede leer temp. Dos funciones pueden tener cada una una variable local total sin compartirla. Cada llamada comienza con variables locales nuevas; una función anidada devuelta puede conservar después el acceso mediante un cierre.

Lee declaraciones antiguas con var
DeclaraciónLímite
let o const dentro de un bloqueEse bloque
var dentro de una funciónLa función que lo contiene, incluso cuando está escrito en un bloque interno
Declaración de nivel superior en un script normalEl ámbito global del script
Declaración de nivel superior en un móduloEse módulo
function test() {
  if (true) {
    var x = 1;
  }
  return x;
}

test() devuelve 1 porque var ignora el límite del if. Sustituirlo por let x = 1; hace que falle el retorno: la x del bloque no está disponible allí. Del mismo modo, for (let i = 0; i < 3; i++) {} mantiene i dentro del bucle, mientras que una var i permanece disponible en la función o el script que la contiene después del bucle y vale 3.

Busca hacia fuera desde la posición donde está escrita la función

Los ámbitos se anidan. Una función interna puede usar nombres de los ámbitos que la contienen, pero el código externo no puede buscar hacia dentro en las variables locales de una función interna. Esto es el ámbito léxico: el lugar donde está escrito el código determina los nombres disponibles.

const level = "global";
function show() {
  return level;
}
function run() {
  const level = "local";
  return show();
}

run() devuelve «global». show se definió fuera de run, por lo que el ámbito que la contiene incluye la level externa. Llamarla desde dentro de run no le da acceso a la level local de quien llama.

Mantén el estado compartido bajo control

Una variable de nivel superior en un script normal es global y las funciones de ese script pueden acceder a ella. Las variables globales compartidas pueden hacer que tareas independientes se afecten entre sí; los scripts de una misma página también pueden entrar en conflicto por los nombres. Pasar entradas y devolver salidas mantiene visibles las dependencias.

Declara todas las variables. En modo estricto, count = 5; genera un ReferenceError si no existe una declaración accesible. Sin modo estricto, una asignación así puede crear una variable global accidental. Un script puede activar el modo estricto con "use strict"; al principio; los módulos lo activan automáticamente. Prefiere const para valores que no se reasignan y let cuando se necesita reasignación.

Puntos clave

  • let y const respetan los límites del bloque; var respeta el límite de la función que lo contiene.
  • Los parámetros y las variables locales de una función no están disponibles para el código externo.
  • El ámbito léxico depende de dónde se define una función, no de dónde se llama.
  • Las variables de nivel superior de un módulo pertenecen al módulo.
  • Declara los nombres explícitamente para evitar asignaciones globales accidentales.

3.2 Predice a qué variable se refiere un nombre

El mismo nombre puede aparecer en varios ámbitos. JavaScript encuentra la declaración correspondiente buscando hacia fuera desde el código actual y deteniéndose en la primera coincidencia.

Sigue la cadena de ámbitos
let x = 1;
function f() {
  let x = 2;
  return x;
}

f() devuelve 2. La declaración local oculta la x externa, por lo que la búsqueda se detiene dentro de f. El valor externo sigue siendo 1. Un parámetro puede ocultar un nombre de la misma manera. Si ningún ámbito de la cadena declara un nombre, leerlo genera un ReferenceError.

Una asignación no declara una variable nueva. Con let count = 0; function add() { count = count + 1; }, add encuentra la declaración externa y la modifica. Añadir let cambia el significado: crea un nuevo nombre local, que puede ocultar precisamente el valor que querías leer.

Distingue el registro de la inicialización

La elevación de declaraciones describe cómo se registran las declaraciones antes de que se ejecute su ámbito. Su comportamiento inicial es diferente:

DeclaraciónAntes de su línea de inicialización
Declaración de funciónSu función está disponible
varSu valor es undefined
let o constAcceder a ella genera un ReferenceError

Por ejemplo, console.log(a); var a = 5; muestra undefined. La asignación del valor 5 aún no se ha producido. En cambio, console.log(b); let b = 5; falla. El intervalo durante el cual el nombre léxico existe pero no se puede acceder a él es su zona muerta temporal, que suele abreviarse como TDZ.

Sigue el sombreado antes de una línea de declaración
let n = 10;
function f() {
  console.log(n);
  let n = 20;
}
f();

La n interna oculta a la externa en todo el cuerpo de la función, incluso antes de la línea donde está escrita la declaración. En console.log(n), ese nombre interno sigue en su zona muerta temporal, por lo que la llamada genera un ReferenceError. JavaScript no pasa por alto una declaración local sin inicializar para recurrir al valor externo 10.

El mismo problema aparece en let count = count + 1; dentro de add. El lado derecho lee la nueva count local antes de que se haya inicializado. Si la intención es actualizar un contador externo, usa una asignación sin una nueva declaración. Si la intención es calcular un valor distinto, dale otro nombre y lee explícitamente el contador externo.

Distingue la reasignación de la mutación

let y const no pueden volver a declarar el mismo nombre en un ámbito; hacerlo produce un SyntaxError. Un ámbito interno puede declarar su propio nombre, lo que constituye sombreado. var permite declaraciones repetidas en su ámbito, lo que dificulta detectar la reutilización accidental de nombres.

const impide reasignar su variable. No congela un array:

const list = [];
list.push(1);

La referencia almacenada en list sigue siendo la misma mientras el array cambia a [1]. list = []; intentaría sustituir la referencia almacenada y fallaría.

Mantén cada declaración en el ámbito más pequeño que la necesite. Usar nombres distintos para tareas distintas reduce la necesidad de seguir mentalmente el sombreado, e inicializar antes de usar evita errores de zona muerta temporal.

Puntos clave

  • La búsqueda de un nombre se detiene en la declaración más cercana de los ámbitos que lo contienen.
  • Una declaración local oculta un nombre externo incluso antes de su inicialización.
  • var comienza como undefined; no se puede acceder a let ni a const en su zona muerta temporal.
  • Una asignación actualiza un enlace existente; una declaración crea uno.
  • const impide la reasignación, pero el contenido de un array aún puede cambiar.
  • Volver a declarar un nombre en un ámbito es distinto de ocultarlo en un ámbito anidado.
4

Usa cierres para dar a las funciones su propia memoria

Una función devuelta puede conservar el acceso a las variables que rodean su definición. Esa conexión conservada da memoria a un contador y permite que una fábrica cree funciones con su propia configuración. Seguirás llamadas separadas a una fábrica, el estado compartido y los cambios posteriores en variables capturadas, y después usarás las mismas reglas para explicar las funciones creadas en un bucle. El estado privado se deriva del ámbito léxico ordinario, incluso después de que termine la llamada externa.

4.1 Explica qué recuerda un cierre

Una función conserva un enlace al ámbito donde se creó. La función y ese acceso conservado forman un cierre. El enlace resulta especialmente útil cuando una función anidada se devuelve y se llama después de que haya terminado su llamada externa.

Da memoria a una función devuelta
function makeCounter() {
  let count = 0;
  return function () {
    count = count + 1;
    return count;
  };
}
const counter = makeCounter();

La llamada a makeCounter crea count, crea una función interna y devuelve esa función. Todavía no ejecuta el cuerpo interno. Ahora counter contiene el valor de la función. Su primera llamada cambia la count conservada de 0 a 1 y devuelve 1. La siguiente cambia la misma variable a 2 y devuelve 2.

El marco de pila de la llamada externa ha terminado, pero la variable capturada sigue siendo accesible. Una variable local que ya no tiene ningún uso accesible puede liberarse; aquí la función interna, a la que aún se puede llamar, sigue necesitándola. El acceso mediante un cierre sobrevive al retorno sin convertir la variable en global.

Crea memorias independientes con llamadas separadas
const a = makeCounter();
const b = makeCounter();
a();
a();
b();

Los resultados son 1, 2 y 1. Cada llamada a la fábrica creó una count diferente. Las dos funciones devueltas por llamadas separadas tienen el mismo código, pero distintos entornos conservados.

Copiar una referencia a una función devuelta funciona de otra manera. Si const alias = a;, entonces alias() usa el contador existente de a; no llama a makeCounter ni crea otro entorno.

Conserva variables, no copias de sus valores
let greeting = "Hi";
const say = () => greeting;
greeting = "Hello";

say() devuelve «Hello». El cierre lee la variable cuando se ejecuta, por lo que una actualización posterior es visible. No almacena una copia fija de «Hi» en el momento de su creación.

El código externo no puede acceder directamente a la count local y counter.count es undefined. Solo el código que tiene acceso a ese entorno léxico puede leerla o actualizarla. Llamar al contador desde una función diferente no cambia qué contador usa.

Comparte estado dentro de una llamada externa
function makeWallet() {
  let balance = 0;
  return [
    function deposit(n) { balance += n; return balance; },
    function getBalance() { return balance; }
  ];
}
const [deposit, getBalance] = makeWallet();
deposit(50);
deposit(20);

getBalance() devuelve 70 porque ambas funciones devueltas se crearon en la misma llamada y se refieren a la misma balance. Otra llamada a makeWallet() crea un saldo separado.

Puntos clave

  • Un cierre conserva el acceso al ámbito donde se creó su función.
  • Una variable capturada puede seguir siendo utilizable después de que termine su llamada externa.
  • Las llamadas separadas a una fábrica crean entornos separados.
  • Los cierres leen los valores actuales de las variables, no copias fijas tomadas al crearse.
  • Las funciones de una misma llamada externa pueden compartir estado privado.

4.2 Usa cierres para crear fábricas de funciones y mantener estado privado

Una fábrica de funciones usa el acceso de los cierres para crear funciones con su propia configuración o estado. Quien llama proporciona la configuración una vez y después usa muchas veces la función devuelta.

Configura una función con un parámetro
function makeMultiplier(factor) {
  return (n) => n * factor;
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);

double(5) devuelve 10 y triple(5) devuelve 15. Cada función flecha devuelta conserva el factor de su propia llamada a la fábrica. La función externa configura el comportamiento; la interna realiza el trabajo repetido.

La forma compacta es const makeMultiplier = (factor) => (n) => n * factor;. Dos flechas significan que se crean dos funciones, no que se hacen dos cálculos consecutivos sobre un número. makeMultiplier(4)(5) primero devuelve una función configurada con 4 y después la llama con 5 para obtener 20.

Aplica una regla al estado privado
function makeLimiter(max) {
  let used = 0;
  return function () {
    if (used >= max) {
      return false;
    }
    used = used + 1;
    return true;
  };
}
const tryLogin = makeLimiter(3);

Las tres primeras llamadas devuelven true e incrementan used. La cuarta devuelve false antes de incrementarla. used es local a la llamada a la fábrica, por lo que el código externo no puede restablecerla mediante ese nombre. La función devuelta controla qué cambios están disponibles. Otro limitador tendría su propia variable used y su propio máximo.

Analiza funciones creadas en bucles
const fns = [];
for (var i = 0; i < 3; i++) {
  fns.push(() => i);
}

El bucle crea tres funciones, pero una sola var i. Después del bucle, esa variable contiene 3. Llamar ahora a cualquiera de las funciones almacenadas devuelve 3 porque todos los cierres leen el mismo enlace actual. Crear una función no evalúa su cuerpo ni guarda una copia del valor actual de i.

Cambiar la cabecera a let i = 0 da al bucle un enlace separado para cada iteración. Las funciones almacenadas devuelven entonces 0, 1 y 2. La misma distinción explica la impresión diferida: una función de devolución de llamada de setTimeout que lee var i después del bucle ve el valor final, mientras que la versión con let conserva el valor de cada iteración.

Reconoce una expresión invocada inmediatamente

El código antiguo suele crear un ámbito de función privado y ejecutarlo inmediatamente:

(function () {
  var hidden = 1;
  console.log(hidden);
})();

Esta es una expresión de función invocada inmediatamente, o IIFE. Los paréntesis exteriores crean una expresión de función; los paréntesis finales la llaman. hidden pertenece a esa función, lo que la mantiene fuera del ámbito global circundante. Es un patrón habitual en código escrito antes de las declaraciones con ámbito de bloque y los módulos.

El acceso conservado también afecta a la memoria. Un cierre al que se puede llamar y que necesita un array grande mantiene esos datos accesibles. Cuando ya no se puede acceder a la función ni a sus datos capturados, estos pueden liberarse. Conserva cierres de larga duración de forma deliberada cuando su memoria forme parte de la tarea.

Puntos clave

  • Las fábricas devuelven funciones configuradas mediante sus argumentos.
  • Las variables privadas se pueden cambiar mediante las operaciones devueltas.
  • Los cierres de un bucle con var comparten un enlace; las iteraciones con let reciben enlaces separados.
  • Una IIFE crea un ámbito de función y lo ejecuta inmediatamente.
  • Los cierres accesibles mantienen accesibles los datos capturados que necesitan.
5

Pasa funciones a otras funciones

Pasar una función permite a quien llama elegir una parte del comportamiento de otra función. Examinarás cómo las funciones receptoras invocan las funciones de devolución de llamada, qué argumentos les proporcionan y cómo usan el resultado. Los métodos de array que ya conoces se convierten en ejemplos de patrones reutilizables de orden superior. Por último, las funciones devueltas envolverán llamadas, conectarán salidas con entradas o mantendrán argumentos seleccionados para usarlos más tarde, combinando valores de función con el acceso que proporcionan los cierres.

5.1 Pasa una función de devolución de llamada a una función

Una función de devolución de llamada es una función que se proporciona como argumento para que otra función la llame. Permite que la función receptora se encargue de la tarea general mientras quien llama proporciona una acción o comprobación concreta.

Pasa una acción a un bucle
function repeat(times, action) {
  for (let i = 0; i < times; i++) {
    action(i);
  }
}
repeat(3, (i) => console.log(i));

repeat controla el bucle y elige los valores 0, 1 y 2. La función flecha determina qué hacer con cada valor: mostrarlo. Cada action(i) llama a la función proporcionada con el número de esa iteración.

Puedes pasar una función existente o escribir una en el punto de uso. repeat(2, sayHi) pasa la función con nombre. repeat(2, (i) => console.log("Round " + (i + 1))) muestra «Round 1» y «Round 2». Una función de devolución de llamada puede ignorar los argumentos que no necesita.

Pasa el valor, sin llamar antes a la función

repeat(3, sayHi()) evalúa sayHi() al preparar los argumentos. Si sayHi solo muestra texto, su valor de retorno es undefined, por lo que repeat recibe ese valor como action. La llamada posterior action(i) falla con un TypeError porque no se puede llamar a undefined como función.

Usa repeat(3, sayHi) para pasar la función. Si la llamada posterior necesita argumentos elegidos, pasa una función envolvente como () => sayHi() para que la llamada ocurra dentro del cuerpo de la función de devolución de llamada. La creación y la invocación de una función son pasos separados.

Comprueba qué argumentos proporciona la función receptora

Las funciones de devolución de llamada de los arrays suelen recibir más de un argumento: el elemento, el índice y el array completo. Pasar una función existente solo es seguro cuando esas entradas corresponden al significado de sus parámetros.

["1", "2", "3"].map(parseInt);

Esto devuelve [1, NaN, NaN]. parseInt acepta un segundo argumento para la base numérica, por lo que el índice del array cambia su comportamiento. Usa ["1", "2", "3"].map((s) => parseInt(s, 10)) para elegir explícitamente la base 10, o .map(Number) para convertir estas cadenas.

Devuelve una respuesta a la función receptora
function countIf(arr, test) {
  let n = 0;
  for (const x of arr) {
    if (test(x)) {
      n++;
    }
  }
  return n;
}

countIf([3, 8, 12, 5], (x) => x > 4) devuelve 3. La función de devolución de llamada responde una pregunta para cada elemento; countIf usa cada respuesta para decidir si incrementa el contador. Compáralo con repeat, cuyo bucle ignora el valor de retorno de la función de devolución de llamada. El código o la documentación de la función receptora indican tanto los argumentos como la función del resultado.

Las funciones de devolución de llamada pueden ejecutarse inmediatamente o más tarde. repeat y los métodos de array las llaman de forma síncrona antes de terminar. setTimeout(sayHi, 2000) programa una para más tarde mientras el código posterior continúa inmediatamente. Ser una función de devolución de llamada describe cómo se proporciona una función, no cuándo debe ejecutarse.

Puntos clave

  • Una función de devolución de llamada se pasa para que otra función la llame.
  • La función receptora controla los argumentos de la función de devolución de llamada y si se usa su resultado.
  • Añadir los paréntesis de llamada demasiado pronto puede pasar un resultado en lugar de una función.
  • Los argumentos de una función de devolución de llamada de un array pueden cambiar el comportamiento de una función existente.
  • Las funciones de devolución de llamada pueden ser síncronas o diferidas.

5.2 Usa y escribe funciones de orden superior

Una función de orden superior acepta una función, devuelve una función o hace ambas cosas. El valor de función proporciona el comportamiento, mientras que la función de orden superior gestiona un patrón reutilizable.

Escribe el patrón una vez
function myMap(arr, transform) {
  const result = [];
  for (const item of arr) {
    result.push(transform(item));
  }
  return result;
}

myMap([1, 2, 3], (n) => n * n) devuelve [1, 4, 9]. El bucle y la construcción del array de salida se mantienen iguales; la función de devolución de llamada decide cómo cambia cada entrada. Un filtro correspondiente añade un elemento solo cuando test(item) es verdadero en contexto booleano. Con [4, 7, 10, 3] y (n) => n % 2 === 0, ese patrón conserva [4, 10].

Elige el contrato de devolución de llamada que necesitas
MétodoFunción de la devolución de llamadaResultado del método
mapDevolver cada valor transformadoUn array nuevo de la misma longitud
filterDevolver un valor verdadero en contexto booleano para los elementos que se conservanUn array nuevo con los elementos seleccionados
findComprobar si un elemento coincideLa primera coincidencia, o undefined
forEachRealizar una acción para cada elementoundefined
reduceDevolver el siguiente acumuladorEl acumulador final

map, filter y find no modifican por sí mismos el array de entrada, pero las funciones de devolución de llamada sí pueden hacerlo. Que un método devuelva un array nuevo no hace que todas las funciones de devolución de llamada proporcionadas sean puras.

Mantén un resultado durante una reducción
[5, 10, 15].reduce((total, n) => total + n, 0);

El acumulador inicial es 0. La función de devolución de llamada devuelve 5 para el primer elemento, 15 para el segundo y 30 para el tercero. Cada valor devuelto se convierte en el total de la siguiente llamada. El método devuelve 30 después del último elemento. Un array vacío sin acumulador inicial hace que reduce genere un TypeError; un valor inicial explícito también define un resultado útil para una entrada vacía.

Devolver arrays permite encadenar llamadas. [3, 8, 12, 5].filter((n) => n > 4).map((n) => n * 2) primero conserva [8, 12, 5] y después lo transforma en [16, 24, 10]. Lee la cadena en orden de ejecución, de izquierda a derecha.

Proporciona una regla de ordenación numérica

Sin un comparador, sort compara las entradas como cadenas. Por tanto, [10, 9, 1].sort() produce [1, 10, 9]. Para ordenar números de forma ascendente, usa .sort((a, b) => a - b). Un retorno negativo coloca a primero, uno positivo coloca b primero y cero deja el par como equivalente para la ordenación. A diferencia de map y filter, sort reorganiza su array de entrada.

Comprueba los valores devueltos

[1, 2, 3].map((n) => { n * 2; }) produce [undefined, undefined, undefined] porque el bloque no tiene retorno. Usar forEach para construir un nuevo resultado mediante una asignación también falla si esperas que el propio método devuelva un array. Elige map para transformar y forEach para acciones cuyos resultados no necesitan recopilarse.

Un método de orden superior expresa claramente un patrón conocido. Un bucle sencillo sigue siendo útil cuando el trabajo necesita break o no encaja en el contrato del método.

Puntos clave

  • Las funciones de orden superior reciben funciones, devuelven funciones o hacen ambas cosas.
  • map, filter y find usan de distintas maneras los resultados de las funciones de devolución de llamada.
  • forEach devuelve undefined; reduce devuelve el acumulador final.
  • Una función de devolución de llamada de reducción debe devolver el siguiente acumulador.
  • La ordenación numérica necesita un comparador y modifica el array original.
  • Un método que devuelve un array nuevo aún puede ejecutar funciones de devolución de llamada con efectos secundarios.

5.3 Construye nuevas funciones a partir de otras existentes

Una función puede devolver una función nueva que recuerda otra existente. Las funciones envolventes, la composición y la aplicación parcial usan este patrón para adaptar el comportamiento sin copiar el cuerpo de la función original.

Envuelve una llamada y conserva su resultado
function logged(fn) {
  return (...args) => {
    console.log("Calling with", args);
    const result = fn(...args);
    console.log("Result", result);
    return result;
  };
}
const add = (a, b) => a + b;

logged(add) crea una función que conserva add como fn. Llamar a logged(add)(2, 3) reúne los argumentos, los pasa a add, muestra el valor devuelto y devuelve 5. El parámetro de resto reúne las entradas de la función envolvente; la propagación las pasa. El retorno final mantiene la salida disponible para cálculos posteriores.

logged(add(2, 3)) pasa el número 5. Llamar después a esa función envolvente intenta llamar a 5 y genera un TypeError. Hay dos etapas: configurar la función envolvente con una función y después llamar a la función devuelta con entradas.

Conserva estado alrededor de una operación
function once(fn) {
  let done = false;
  let result;
  return (...args) => {
    if (!done) {
      done = true;
      result = fn(...args);
    }
    return result;
  };
}

Para una operación que termina normalmente, la primera llamada ejecuta fn y almacena su resultado. Las llamadas posteriores devuelven ese valor almacenado sin volver a ejecutar fn, aunque sus argumentos sean diferentes. El booleano registra si la operación se ejecutó; comprobar si el resultado es verdadero en contexto booleano sería incorrecto cuando un resultado válido es 0 o false. Cada llamada a once crea su propio indicador y resultado almacenado.

Pasa un resultado a otra función
const compose = (f, g) => (x) => f(g(x));
const addOne = (n) => n + 1;
const square = (n) => n * n;

compose(square, addOne)(3) ejecuta primero addOne(3) y después eleva 4 al cuadrado para devolver 16. compose(addOne, square)(3) primero eleva 3 al cuadrado y después suma 1, y devuelve 10. La función más cercana a la entrada se ejecuta primero, por lo que importa el orden de los argumentos de compose.

Fija algunos argumentos de antemano
function partial(fn, ...fixed) {
  return (...rest) => fn(...fixed, ...rest);
}
const greetWith = (greeting, name) => greeting + ", " + name;
const hello = partial(greetWith, "Hello");

hello("Ana") llama a greetWith("Hello", "Ana") y devuelve «Hello, Ana». Esta función auxiliar de aplicación parcial coloca primero los argumentos fijos y después los argumentos posteriores; cambiar ese orden modifica la llamada subyacente.

Puntos clave

  • Una función envolvente conserva una función y añade comportamiento alrededor de su llamada.
  • El resto y la propagación permiten que una función envolvente pase argumentos separados.
  • Devolver el resultado de la función envuelta permite que quien llama lo use.
  • Una función envolvente de ejecución única conserva tanto un indicador como el primer resultado.
  • compose(f, g) aplica g antes que f.
  • La aplicación parcial fija determinados argumentos antes de llamadas posteriores.

Ejemplos de Funciones en JavaScript

5 Lecciones Interactivas

1

Crea, almacena y llama a una función

11 pasos
Sigue un saludo reutilizable mediante declaraciones, valores de función y cuerpos de funciones flecha.
  1. 1
    IntroducciónDistingue la receta de la llamada

    Una función almacena instrucciones para que varias llamadas puedan reutilizarlas. Su definición describe una tarea; una llamada realiza esa tarea con entradas concretas.

    Sigue un saludo en tres formas: una declaración, una expresión almacenada en una variable y una función flecha. Observa dos detalles a medida que cambia la sintaxis: cuándo está disponible la función y si su cuerpo devuelve un valor.

  2. 2
    EjemploDefine un saludo
    function greet(name) {
      console.log("Hello, " + name + "!");
    }
    

    La palabra clave, el nombre, la lista de parámetros y el cuerpo forman una declaración. Todavía no se ha mostrado nada: la definición almacena las instrucciones.

    name es un parámetro cuyo valor llegará desde una llamada. El cuerpo se puede reutilizar porque describe cómo construir el saludo sin elegir de antemano el nombre de una persona.

  3. 3
    EjemploEjecuta las instrucciones almacenadas
    greet("Amira");
    greet("Li");
    

    Las llamadas muestran «Hello, Amira!» y «Hello, Li!» en líneas separadas. Cada una inicia de nuevo el mismo cuerpo con su propia entrada.

    La expresión greet por sí sola es el valor de la función. Los paréntesis de greet("Li") solicitan su ejecución. Incluso una función sin entradas necesita paréntesis de llamada, como en sayHi().

  4. 4
    DesafíoPredice la llamada anticipada

    ¿Qué se muestra cuando se ejecuta este script?

    show();
    function show() { console.log("Ready"); }
    

    ---reveal---

    Muestra «Ready» una vez. La declaración se eleva dentro de su ámbito, por lo que la función está disponible en la primera línea. La elevación no ejecuta el cuerpo por sí sola: lo hace la llamada explícita show(). Una línea que contuviera solo show; leería la función sin mostrar nada.

  5. 5
    ExplicaciónConserva la función como valor
    const square = function (n) {
      return n * n;
    };
    const alias = square;
    

    La expresión crea una función y square la almacena. La segunda asignación copia su referencia en alias; no calcula un cuadrado. Tanto square(3) como alias(3) devuelven 9.

    En comparación, const answer = square(3); llama a la función y almacena el número devuelto.

  6. 6
    DesafíoLocaliza el primer fallo

    ¿Este script muestra 16?

    console.log(square(4));
    const square = function (n) { return n * n; };
    

    ---reveal---

    No. Leer square antes de su inicialización con const genera un ReferenceError. La asignación no se ha ejecutado, por lo que el valor de función de la expresión no está disponible. Mueve la llamada debajo de la asignación o usa una declaración de función si necesitas poder llamarla antes en este ámbito.

  7. 7
    EjemploUsa una función flecha concisa
    const square = (n) => n * n;
    const add = (a, b) => a + b;
    

    El cuerpo conciso de una función flecha devuelve su expresión, por lo que square(4) devuelve 16 y add(2, 3) devuelve 5.

    Un solo parámetro simple puede omitir los paréntesis: n => n * n. Las listas vacías, varios parámetros, los valores predeterminados y los parámetros de resto los necesitan. Las funciones flecha son expresiones, por lo que estas variables const siguen necesitando inicializarse antes de usarlas.

  8. 8
    DesafíoCorrige un resultado ausente

    ¿Por qué add(2, 3) devuelve undefined y qué cambio hace que devuelva 5?

    const add = (a, b) => { a + b; };
    

    ---reveal---

    Las llaves comienzan un bloque, por lo que la expresión se evalúa, pero no se devuelve. Escribe (a, b) => { return a + b; } o elimina las llaves para usar (a, b) => a + b. Ambas correcciones devuelven la suma. Añadir solo un punto y coma después de la asignación no cambia el comportamiento de retorno del cuerpo.

  9. 9
    ConsejoDevuelve una expresión de objeto
    const makePoint = (x, y) => ({ x: x, y: y });
    

    Los paréntesis hacen que el literal de objeto sea una expresión devuelta por el cuerpo conciso. Una llave de apertura sin paréntesis comenzaría un bloque.

    Las funciones flecha no tienen sus propios this ni arguments y no pueden ser constructores. La forma corta funciona bien para cálculos sencillos, pero esas diferencias importan al convertir otros tipos de funciones.

  10. 10
    DesafíoSigue una función y su alias

    ¿Qué devuelve copy(5)?

    const adjust = (n) => { return n + 2; };
    const copy = adjust;
    

    ---reveal---

    Devuelve 7. El bloque de la función flecha contiene un retorno explícito y copy contiene la misma función invocable que adjust. La asignación no llamó a la función ni almacenó un resultado numérico. Sustituir const copy = adjust; por const copy = adjust(5); almacenaría 7, que no se puede llamar como función.

  11. 11
    RepasoIdentifica la operación de cada línea

    Una declaración crea una tarea con nombre que está disponible desde el principio de su ámbito. Una expresión crea un valor de función cuando la ejecución llega a ella. El cuerpo conciso de una función flecha devuelve un valor automáticamente; su cuerpo de bloque necesita return.

    Al seguir el código, distingue entre una definición de función, una asignación de referencia y una llamada. Son operaciones diferentes aunque usen el mismo nombre.

2

Sigue entradas, salidas y llamadas en espera

16 pasos
Relaciona argumentos, sigue valores devueltos y resuelve un breve cálculo recursivo.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónSigue lo que entra y sale de una llamada
  2. 2
    EjemploRelaciona los argumentos por posición
  3. 3
    EjemploDistingue la mutación de la reasignación
  4. 4
    DesafíoConserva la entrada original
  5. 5
    ExplicaciónEl valor predeterminado se aplica a undefined
  6. 6
    EjemploReúne y después expande
  7. 7
    DesafíoUsa un valor predeterminado con un parámetro de resto
  8. 8
    EjemploDevuelve el número que necesita quien llama
  9. 9
    EjemploDetén una ruta con un retorno anticipado
  10. 10
    DesafíoEvalúa de dentro hacia fuera
  11. 11
    EjemploRecuerda la llamada pendiente
  12. 12
    ExplicaciónDa a la recursión una vía de parada
  13. 13
    EjemploResuelve los productos en espera
  14. 14
    DesafíoCorrige un límite recursivo
  15. 15
    ConexiónInterpreta un fallo mediante la pila
  16. 16
    RepasoSigue un valor a través de cada límite
3

Encuentra la declaración detrás de un nombre

10 pasos
Sigue los límites de bloque, la búsqueda léxica y el momento de inicialización.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónPregúntate a dónde pertenece el nombre
  2. 2
    EjemploCompara los límites de bloque y de función
  3. 3
    EjemploUsa la ubicación de la definición
  4. 4
    DesafíoSigue un valor local y otro externo
  5. 5
    ExplicaciónDetente en la declaración más cercana
  6. 6
    Idea claveEstar registrada no significa estar inicializada
  7. 7
    DesafíoPredice la lectura de un nombre ocultado
  8. 8
    ConsejoDistingue la reasignación de la mutación
  9. 9
    DesafíoCombina una función de devolución de llamada con el momento de búsqueda
  10. 10
    RepasoSigue la ubicación antes que el valor
4

Da a las funciones devueltas su propia memoria

11 pasos
Sigue el estado compartido e independiente de los cierres y después examina las funciones creadas dentro de un bucle.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónConserva el acceso después de un retorno
  2. 2
    EjemploCrea un contador sin llamarlo
  3. 3
    EjemploActualiza la variable conservada
  4. 4
    DesafíoCompara contadores independientes
  5. 5
    Idea claveConserva el enlace, no una copia fija
  6. 6
    EjemploCrea un cálculo configurado
  7. 7
    EjemploMantén un contador de usos privado
  8. 8
    DesafíoExplica tres resultados iguales
  9. 9
    ConexiónReconoce el ámbito privado en código antiguo
  10. 10
    DesafíoComparte una operación configurada
  11. 11
    RepasoSigue cuántos entornos existen
5

Pasa comportamiento y construye funciones adaptadas

15 pasos
Sigue los argumentos de las funciones de devolución de llamada, los resultados de los métodos de array y las funciones que devuelven funciones configuradas.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónDeja que una función proporcione el comportamiento variable
  2. 2
    EjemploLlama a la acción proporcionada
  3. 3
    DesafíoUsa el resultado de una función de devolución de llamada
  4. 4
    ConsejoExamina todos los argumentos de la función de devolución de llamada
  5. 5
    EjemploEscribe un patrón de transformación
  6. 6
    ExplicaciónElige la forma del resultado
  7. 7
    DesafíoSigue una selección y una transformación
  8. 8
    Idea claveControla el orden numérico
  9. 9
    EjemploEnvuelve y transmite una llamada
  10. 10
    ExplicaciónRecuerda si una llamada se ha ejecutado
  11. 11
    EjemploCompón de dentro hacia fuera
  12. 12
    EjemploFija entradas antes de la llamada posterior
  13. 13
    DesafíoPasa una función de devolución de llamada configurada
  14. 14
    DesafíoRecupera un resultado perdido en una función envolvente
  15. 15
    RepasoComprueba ambas etapas del código de orden superior

Ejercicios de Funciones en JavaScript

50 Preguntas de Práctica en 5 sets

Set 1: Elige entradas y sigue el estado conservado10 Preguntas de Práctica

Pregunta 1 de 10

¿Qué ocurre cuando se ejecuta este script?

announce();
function announce() { console.log("Open"); }
  1. Genera un ReferenceError.
  2. Muestra undefined una vez.
  3. Muestra «Open» una vez.
  4. Genera un TypeError.
Mostrar respuestaOcultar respuesta
Respuesta: C
La declaración se eleva dentro del ámbito del script, por lo que announce ya es una función cuando la primera línea la llama. Su cuerpo muestra «Open» una vez. El momento de inicialización de una expresión de función almacenada en const sería diferente, pero este código usa una declaración.

Pregunta 2 de 10

¿Cómo puede una función flecha devolver un objeto con una propiedad value igual a su entrada n?
  1. (n) => ({ value: n })
  2. (n) => { return; value: n; }
  3. (n) => (value = n)
  4. (n) => { value: n }
Mostrar respuestaOcultar respuesta
Respuesta: A
Los paréntesis hacen que { value: n } sea una expresión de objeto, que el cuerpo conciso de la función flecha devuelve. Sin esos paréntesis, las llaves comienzan un bloque y value: n se interpreta como una sentencia etiquetada, sin devolver ningún objeto. Un return; sin valor también devuelve undefined.

Pregunta 3 de 10

¿Qué devuelve la llamada?

function combine(first, ...rest) {
  return first + rest.length;
}
const values = [8, 2, 6];
combine(...values);
  1. 16
  2. 8
  3. 11
  4. 10
Mostrar respuestaOcultar respuesta
Respuesta: D
La propagación pasa tres argumentos separados. El parámetro fijo recibe 8 y el parámetro de resto reúne [2, 6], cuya longitud es 2, por lo que la función devuelve 10. Contar los tres valores en rest daría 11, pero el primer argumento ya se ha asignado a first.

Pregunta 4 de 10

¿Qué devuelve guarded(0)?

function guarded(n) {
  if (n === 0) { return "empty"; }
  return "filled";
}
  1. "filled"
  2. "empty"
  3. ["empty", "filled"]
  4. undefined
Mostrar respuestaOcultar respuesta
Respuesta: B
La condición es verdadera para 0, por lo que el primer retorno termina inmediatamente la llamada con «empty». La ejecución no continúa hasta el retorno posterior. Una función devuelve un valor para una llamada concreta; dos sentencias de retorno describen distintas rutas posibles, no una lista de salidas recopiladas.

Pregunta 5 de 10

¿Qué devuelve totalDown(3)?

function totalDown(n) {
  if (n === 0) { return 0; }
  return n + totalDown(n - 1);
}
  1. 0
  2. 6
  3. 9
  4. 3
Mostrar respuestaOcultar respuesta
Respuesta: B
Las llamadas llegan a totalDown(0), que devuelve 0. Las llamadas en espera devuelven después 1, 3 y 6. El retorno del caso base no sustituye el resultado de todas las llamadas por 0; cada marco en espera sigue teniendo su propia n y debe completar su suma pendiente.

Pregunta 6 de 10

¿Qué ocurre cuando se llama a read()?

let label = "outer";
function read() {
  return label;
  let label = "inner";
}
  1. Devuelve la cadena «inner».
  2. Devuelve la cadena «outer».
  3. Genera un ReferenceError.
  4. Devuelve el valor undefined.
Mostrar respuestaOcultar respuesta
Respuesta: C
La declaración local oculta la label externa en todo read, incluido el retorno anterior. Esa variable local todavía no está inicializada, por lo que leerla genera un ReferenceError. La asignación inalcanzable no hace que JavaScript omita la declaración local y use la cadena externa.

Pregunta 7 de 10

¿Qué devuelve la llamada final?

let word = "first";
const read = () => word;
word = "second";
function run() {
  const word = "third";
  return read();
}
run();
  1. "second"
  2. undefined
  3. "first"
  4. "third"
Mostrar respuestaOcultar respuesta
Respuesta: A
read conserva acceso a la word del nivel superior, cuyo valor actual es «second». No conserva una copia fija de «first», y llamarla desde run no dirige su búsqueda a la «third» local de quien llama. Tanto la ubicación de la definición como la asignación posterior importan.

Pregunta 8 de 10

¿Qué array produce la expresión final?

const readers = [];
for (let i = 1; i <= 3; i++) {
  let value = i;
  readers.push(() => value);
  value += 10;
}
readers.map((read) => read());
  1. [13, 13, 13]
  2. [1, 2, 3]
  3. [14, 14, 14]
  4. [11, 12, 13]
Mostrar respuestaOcultar respuesta
Respuesta: D
Cada iteración crea su propia value y su función conserva ese enlace. La suma posterior en esa misma iteración cambia el valor que leerá la función a 11, 12 o 13. [1, 2, 3] trataría la creación del cierre como una copia fija e ignoraría esas actualizaciones posteriores.

Pregunta 9 de 10

¿Qué ocurre cuando se ejecuta la última línea?

function speak() { console.log("Hi"); }
function twice(action) { action(); action(); }
twice(speak());
  1. Muestra «Hi» una vez y después genera un TypeError.
  2. Genera un TypeError antes de mostrar nada.
  3. Muestra «Hi» dos veces y después termina normalmente.
  4. Muestra «Hi» tres veces y después termina normalmente.
Mostrar respuestaOcultar respuesta
Respuesta: A
Preparar el argumento llama inmediatamente a speak, por lo que «Hi» se muestra una vez. Su valor de retorno es undefined, que se convierte en action; el primer intento de ejecutar action() genera entonces un TypeError. Pasar speak sin paréntesis de llamada permitiría que twice la invocara dos veces.

Pregunta 10 de 10

¿Cuál es el resultado final?

const compose = (f, g) => (x) => f(g(x));
const subtract = (n) => n - 2;
const triple = (n) => n * 3;
const first = compose(triple, subtract);
const second = compose(subtract, triple);
first(second(4));
  1. 18
  2. 28
  3. 24
  4. 30
Mostrar respuestaOcultar respuesta
Respuesta: C
second(4) triplica 4 y resta 2, por lo que devuelve 10. Ese valor se convierte en la entrada de first, que resta 2 y triplica 8, y devuelve 24. Un resultado de 18 aplica first y second en el orden externo inverso; cada composición también debe mantener su propio orden de llamada, de dentro hacia fuera.
Set 2: Lee funciones y sigue sus valores10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿Cuál es el valor final de result?

const values = [2, 7, 4, 9];
const result = values
  .filter((n) => n > 3)
  .map((n) => n - 1)
  .reduce((total, n) => total + n, 5);
  1. 27
  2. 22
  3. 17
  4. 21
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Dada function showLabel() { console.log("Ready"); }, ¿qué sentencia llama a la función?
  1. "showLabel";
  2. showLabel();
  3. showLabel;
  4. const label = showLabel;
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Qué contiene copy después de este código?

const triple = function (n) { return n * 3; };
const copy = triple;
  1. El valor undefined hasta que se llame a copy.
  2. Una función independiente con estado privado copiado.
  3. El número devuelto al llamar a triple(3).
  4. Una referencia a la misma función que triple.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Qué devuelve adjust(8)?

const adjust = (n) => { n - 3; };
  1. undefined
  2. 5
  3. 8
  4. NaN
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

¿Qué devuelve difference(12, 5)?

function difference(first, second) {
  return first - second;
}
  1. 17
  2. undefined
  3. 7
  4. -7
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

¿Qué devuelve readLevel(0)?

function readLevel(level = 40) { return level; }
  1. 40
  2. undefined
  3. null
  4. 0
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

¿Qué número se muestra y cuál es el valor de result?

function displayTotal(a, b) { console.log(a + b); }
const result = displayTotal(6, 9);
  1. Muestra 15; result vale 15.
  2. Muestra 15; result vale undefined.
  3. No muestra nada; result vale 15.
  4. Muestra undefined; result vale 15.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

¿Qué ocurre cuando se llama a getFlag()?

function getFlag() {
  if (true) { let flag = "on"; }
  return flag;
}
  1. Genera un ReferenceError.
  2. Genera un TypeError.
  3. Devuelve el valor undefined.
  4. Devuelve la cadena «on».
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

¿Qué valores devuelven las dos llamadas, en orden?

function makeStep() {
  let value = 4;
  return () => { value += 2; return value; };
}
const step = makeStep();
step();
step();
  1. 4, 6
  2. 8, 10
  3. 6, 8
  4. 6, 6
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

¿Cuál es la secuencia completa de valores mostrados?

function deliver(action) { action(7); }
console.log("start");
deliver((n) => console.log(n));
console.log("end");
  1. "start", 7, "end"
  2. "start", undefined, "end"
  3. "start", "end", 7
  4. 7, "start", "end"
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 3: Relaciona llamadas, ámbito y funciones de devolución de llamada10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿Qué valor se asigna a out?

const describe = (n) => {
  const doubled = n * 2;
  return doubled + 1;
};
const out = describe(6);
  1. undefined
  2. 7
  3. 13
  4. 12
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Qué ocurre cuando se ejecuta este script?

const saved = build;
const build = function () { return 9; };
console.log(saved());
  1. Genera un ReferenceError en la primera línea.
  2. Genera un TypeError en la última línea.
  3. Muestra undefined en la última línea.
  4. Muestra 9 después de completar la asignación.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Qué valores tienen items y answer después de este código?

const items = [5];
function change(list) {
  list.push(8);
  list = [1];
  return list;
}
const answer = change(items);
  1. items es [5, 8]; answer es [5, 8].
  2. items es [5]; answer es [1].
  3. items es [1]; answer es [1].
  4. items es [5, 8]; answer es [1].
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Qué devuelve countLeaves([0, [[], 2], [[3], 4]])?

function countLeaves(list) {
  let count = 0;
  for (const item of list) {
    if (Array.isArray(item)) {
      count += countLeaves(item);
    } else {
      count++;
    }
  }
  return count;
}
  1. 6
  2. 4
  3. 3
  4. 5
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

¿Qué devuelve readValue()?

function readValue() {
  if (true) { var value = 14; }
  return value;
}
  1. 14
  2. undefined
  3. Genera un ReferenceError.
  4. Genera un TypeError.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

¿Cuáles son los dos valores mostrados?

let count = 2;
function update() {
  let count = 7;
  count += 1;
  return count;
}
console.log(update());
console.log(count);
  1. 3, 3
  2. 7, 2
  3. 8, 2
  4. 8, 8
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

¿Qué valores devuelven las tres últimas llamadas?

function makeCounter(start) {
  let n = start;
  return () => { n++; return n; };
}
const a = makeCounter(5);
const alias = a;
const b = makeCounter(5);
a();
alias();
b();
  1. 5, 6, 5
  2. 6, 7, 6
  3. 6, 7, 8
  4. 6, 6, 6
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

¿Qué devuelve scale(7)?

const makeScale = (factor) => (n) => n * factor;
const scale = makeScale(4);
  1. 7
  2. 11
  3. Una función nueva.
  4. 28
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

¿Qué valores tienen values y first después?

const values = [12, 3, 20];
const first = values.sort((a, b) => a - b)[0];
  1. values es [12, 3, 20]; first vale 3.
  2. values es [3, 12, 20]; first vale 3.
  3. values es [20, 12, 3]; first vale 20.
  4. values es [12, 20, 3]; first vale 12.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

¿Qué devuelven las llamadas read(0) y read(9), en orden?

function once(fn) {
  let done = false;
  let result;
  return (...args) => {
    if (!done) {
      done = true;
      result = fn(...args);
    }
    return result;
  };
}
const read = once((n) => n * 2);
  1. undefined, 18
  2. 0, 18
  3. 0, 0
  4. 0, undefined
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 4: Analiza el comportamiento de funciones en programas pequeños10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Un script define function printLine() { console.log("---"); } y después ejecuta printline();. ¿Qué ocurre?
  1. La llamada devuelve undefined sin mostrar nada.
  2. Se muestra una línea y la ejecución continúa.
  3. Ocurre un TypeError y no se muestra ninguna línea.
  4. Ocurre un ReferenceError y no se muestra ninguna línea.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Qué devuelve la llamada final?

const climb = function step(n) {
  return n === 0 ? 0 : 1 + step(n - 1);
};
const saved = climb;
saved(2);
  1. 0
  2. 2
  3. Genera un ReferenceError.
  4. 1
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Qué valores tienen data y result al final?

const data = [2, 5];
function extend(list, item) {
  const next = list.concat(item);
  list.push(9);
  return next;
}
const result = extend(data, 7);
result.push(1);
  1. data es [2, 5, 9]; result es [2, 5, 7, 1].
  2. data es [2, 5, 9, 1]; result es [2, 5, 7, 1].
  3. data es [2, 5, 7, 9]; result es [2, 5, 7, 9, 1].
  4. data es [2, 5]; result es [2, 5, 7, 9, 1].
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Qué devuelve la llamada final?

function total(base = 4, ...extras) {
  return extras.reduce((sum, n) => sum + n, base);
}
const values = [undefined, 3, 0, 8];
total(...values);
  1. NaN
  2. 11
  3. 15
  4. 19
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

¿Qué valor produce esta llamada?

function read() {
  return;
}
read();
  1. undefined
  2. null
  3. false
  4. 0
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

La entrada n es un entero no negativo. ¿Qué sustitución del retorno recursivo hace que la función cuente hacia atrás hasta 0 correctamente tanto para entradas impares como pares?

function countDown(n) {
  if (n === 0) { return 0; }
  // recursive return goes here
}
  1. return 1 + countDown(n - 2);
  2. return 1 + countDown(n - 1);
  3. return 1 + countDown(n);
  4. return 1 + countDown(n + 1);
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

¿Qué devuelve la llamada final?

const mode = "shared";
function readMode() { return mode; }
function run() {
  const mode = "local";
  return readMode();
}
run();
  1. Genera un ReferenceError.
  2. undefined
  3. "local"
  4. "shared"
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

¿Qué valores devuelven jobs[0]() y jobs[1]() después del bucle?

const jobs = [];
for (var i = 0; i < 2; i++) {
  const offset = i * 10;
  jobs.push(() => offset + i);
}
  1. 12, 12
  2. 0, 10
  3. 2, 12
  4. 0, 11
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

¿Qué resultado produce esta expresión?

["6", "8", "10"].map((text) => parseInt(text, 10));
  1. [6, NaN, NaN]
  2. [6, 8, 10]
  3. [6, NaN, 2]
  4. ["6", "8", "10"]
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

¿Qué valores de out y seen se muestran?

let seen = 0;
const out = [3, 5].forEach((n) => {
  seen += n;
  return n * 2;
});
console.log(out, seen);
  1. undefined, 8
  2. [6, 10], 8
  3. undefined, 16
  4. [6, 10], 0
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 5: Combina cierres y funciones de orden superior10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿A qué valor se evalúa add("6", 4) * 2?

function add(a, b) { return a + b; }
  1. 20
  2. NaN
  3. 128
  4. "6464"
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Qué función flecha devuelve la suma de sus dos entradas?
  1. (a, b) => { console.log(a + b); }
  2. (a, b) => { return a + b; }
  3. (a, b) => { return; a + b; }
  4. (a, b) => { a + b; }
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿A qué valor se evalúa la expresión final?

function choose(n) {
  if (n < 0) { return 0; }
  return n + 2;
}
choose(choose(-4));
  1. 2
  2. -2
  3. 0
  4. 4
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Qué ocurre cuando se llama a build()?

let amount = 6;
function build() {
  const read = () => amount;
  const result = read();
  let amount = 9;
  return result;
}
  1. Devuelve el número 6.
  2. Devuelve el número 9.
  3. Devuelve el valor undefined.
  4. Genera un ReferenceError dentro de read.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

¿Qué valores devuelven change(3), read() y otherRead()?

function makePair() {
  let n = 1;
  return [
    (step) => { n += step; return n; },
    () => n
  ];
}
const [change, read] = makePair();
const [, otherRead] = makePair();
  1. 4, 1, 1
  2. 4, 4, 4
  3. 3, 3, 1
  4. 4, 4, 1
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

¿Qué devuelve la expresión final?

function makeLimit(max) {
  let used = 0;
  return () => {
    if (used >= max) { return false; }
    used++;
    return true;
  };
}
const allow = makeLimit(2);
[allow(), allow(), allow()];
  1. [true, true, true]
  2. [true, true, false]
  3. [true, false, false]
  4. [false, false, false]
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

¿Qué valores tienen result y calls después de este código?

let calls = 0;
function choose(values, test) {
  for (const value of values) {
    calls++;
    if (test(value)) { return value; }
  }
  return null;
}
const result = choose([3, 8, 10, 5], (n) => n > 6 && n % 2 === 0);
  1. result vale 8; calls vale 2.
  2. result es [8, 10]; calls vale 4.
  3. result vale 8; calls vale 4.
  4. result vale 10; calls vale 3.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

¿Qué valores tienen items y out después?

const items = [2, 4, 6];
const out = items.map((n, index, array) => {
  array[index] = n + 1;
  return n * 2;
});
  1. items es [4, 8, 12]; out es [3, 5, 7].
  2. items es [3, 5, 7]; out es [6, 10, 14].
  3. items es [3, 5, 7]; out es [4, 8, 12].
  4. items es [2, 4, 6]; out es [4, 8, 12].
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

¿Qué devuelve doubleSaved(9) después de la llamada anterior mostrada?

function once(fn) {
  let done = false;
  let saved;
  return (...args) => {
    if (!done) { done = true; saved = fn(...args); }
    return saved;
  };
}
const compose = (f, g) => (x) => f(g(x));
const saved = once((n) => n + 3);
const doubleSaved = compose((n) => n * 2, saved);
saved(4);
doubleSaved(9);
  1. 18
  2. 14
  3. 7
  4. 24
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

¿Cuál es el array devuelto?

const partial = (fn, ...fixed) => (...later) => fn(...fixed, ...later);
const offset = (base, n) => base + n;
const addFive = partial(offset, 5);
const compose = (f, g) => (x) => f(g(x));
const transform = compose((n) => n * n, addFive);
[1, 3].map(transform);
  1. [12, 16]
  2. [6, 14]
  3. [36, 64]
  4. [26, 28]
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

¿Te atascas con una pregunta tuya? Ayuda con Tareas

Términos Clave

66 Términos Clave, cada uno con su definición

A

Acumulador
Un acumulador es el resultado acumulado en una reducción, que se pasa a la función de devolución de llamada y se sustituye en cada paso por el valor que esta devuelve.
Una reducción de suma que comienza en 0 actualiza su acumulador a 5, 15 y 30 mientras procesa [5, 10, 15].
Aplicación parcial
La aplicación parcial fija determinados argumentos de antemano y devuelve una función que proporciona las entradas restantes cuando se la llama más tarde.
Una función de saludo a la que se ha aplicado parcialmente «Hello» puede aceptar después «Ana» y devolver «Hello, Ana».
Argumento
Un argumento es un valor proporcionado en una llamada a función, que se relaciona por posición con un parámetro o se recopila entre las entradas restantes.
En area(4, 2.5), los argumentos son 4 y 2,5, independientemente de los nombres que se hayan dado a los parámetros.

Á

Ámbito de bloque
El ámbito de bloque limita una declaración let o const al bloque que la contiene y al código anidado, y deja esa declaración inaccesible para el código externo.
Una let message declarada en el cuerpo de un if no puede ser leída por una sentencia posterior al final de ese bloque.
Ámbito de función
El ámbito de función hace que un parámetro o una declaración var sean locales a la función que los contiene, incluso cuando var está escrito dentro de un bloque interno.
Una var result a la que se asigna un valor en un bloque if puede devolverse más tarde desde el cuerpo de la función que la contiene.
Ámbito global
El ámbito global contiene las declaraciones de nivel superior de un script normal y pone esos nombres a disposición de las funciones cuyas cadenas de ámbitos llegan a ellos.
La variable count de nivel superior de un script puede convertirse en estado compartido cuando varias funciones la leen o actualizan.
Ámbito léxico
El ámbito léxico determina las declaraciones externas accesibles a partir de cómo está anidado el código escrito, en lugar de hacerlo a partir de la ubicación de una llamada posterior.
Una función lectora de nivel superior sigue leyendo su variable externa cuando se la llama dentro de una función con una variable local del mismo nombre.

C

Cadena de ámbitos
La cadena de ámbitos es la secuencia formada por el ámbito actual y los que lo contienen, que se busca hacia fuera para resolver un nombre y se detiene en la primera declaración.
Un cálculo interno lee su amount local antes de considerar una variable del mismo nombre en un ámbito externo.
Cadena de métodos
Una cadena de métodos usa el valor devuelto por un método como receptor del siguiente, lo que permite realizar varios pasos de procesamiento de arrays en secuencia.
Un filtro seguido de una transformación selecciona primero las entradas y después transforma solo los elementos conservados.
Caso base
Un caso base es la ruta de parada de una función recursiva, que devuelve un valor sin otra llamada a sí misma cuando el problema ha alcanzado una forma sencilla.
Para un factorial de enteros no negativos, la comprobación n <= 1 detiene las llamadas tanto en 0 como en 1.
Caso recursivo
Un caso recursivo aborda el problema llamando a la misma función con una entrada reducida y usa el resultado devuelto para terminar la llamada actual.
La expresión n * factorial(n - 1) espera el factorial más pequeño antes de multiplicarlo por la n de esta llamada.
Cierre
Un cierre combina una función con el acceso conservado a su ámbito de creación, lo que permite que las variables capturadas sigan siendo utilizables después de un retorno externo.
Una función de contador puede seguir incrementando su count privada después de que haya terminado la fábrica que la creó.
Cláusula de guarda
Una cláusula de guarda comprueba una condición especial y sale anticipadamente, manteniendo esa ruta excepcional separada del trabajo principal de la función.
La comprobación if (b === 0) { return null; } protege la división que aparece después en safeDivide.
Comparador
Un comparador es una función de devolución de llamada de ordenación cuyo valor de retorno negativo, positivo o cero determina el orden relativo de dos entradas comparadas.
El comparador (a, b) => a - b ordena números de forma ascendente mientras sort reorganiza el array de entrada.
Composición
La composición combina funciones pasando la salida de una función a la entrada de otra, de modo que la llamada interna se realiza antes que la externa.
Con f(g(x)), cambiar el orden a g(f(x)) puede cambiar el resultado incluso cuando ambas funciones aceptan números.
Cuerpo conciso
Un cuerpo conciso es un cuerpo de función flecha formado por una expresión cuyo valor se convierte en el resultado de la llamada sin una sentencia return explícita.
El cuerpo de expresión de (a, b) => a + b devuelve directamente la suma de los dos argumentos proporcionados.
Cuerpo de bloque
Un cuerpo de bloque contiene sentencias entre llaves y requiere un return explícito para devolver un valor calculado desde una función flecha.
La función flecha (n) => { n * 2; } calcula un producto, pero devuelve undefined porque no tiene una sentencia de retorno.
Cuerpo de función
El cuerpo de una función contiene las instrucciones que se ejecutan durante una llamada; una función ordinaria encierra esas sentencias entre llaves.
Si un cuerpo de printHeading contiene tres sentencias que muestran valores, las tres se ejecutan de nuevo en cada llamada a esa función.

D

Declaración de función
Una declaración de función define una función con nombre mediante la palabra clave function y la pone a disposición desde el comienzo de su ámbito.
La llamada greet("Li") puede aparecer antes de la declaración escrita de greet en el mismo ámbito.
Desestructuración de arrays
La desestructuración de arrays asigna entradas de un array a nombres individuales, lo que permite que un array devuelto proporcione varios resultados con nombre.
La declaración const [low, high] = minMax(values); extrae las dos entradas del array devuelto.

E

Efecto secundario
Un efecto secundario es un cambio fuera del cálculo local de una función, como mostrar valores, cambiar una variable externa o modificar un array de entrada.
Una función de devolución de llamada que añade elementos a una lista compartida tiene un efecto secundario aunque también devuelva un valor útil.
Elevación de declaraciones
La elevación de declaraciones describe el registro de las declaraciones antes de que se ejecute su ámbito, con distintas reglas de acceso anticipado para funciones, var, let y const.
Leer una variable var elevada antes de su asignación da undefined; una llamada anticipada a una declaración de función puede ejecutarse.
Enlace
Un enlace asocia un nombre con un valor almacenado en un ámbito concreto, lo que permite que las variables del mismo nombre en ámbitos distintos permanezcan separadas.
Una asignación actualiza el enlace accesible más cercano; una declaración interna crea uno local separado.
Enlace por iteración
Un enlace por iteración es el enlace separado de una variable de bucle que let crea para una iteración en la cabecera de un bucle for y que los cierres pueden conservar.
Las funciones flecha almacenadas de distintas iteraciones de let i pueden devolver valores diferentes después de que termine el bucle.
Estado compartido
El estado compartido son datos conservados a los que más de una función puede acceder y actualizar, como un enlace capturado por funciones de una misma llamada.
Una operación de depósito y una función que lee el saldo, devueltas juntas, pueden acceder a la misma balance privada.
Estado privado
El estado privado son datos dentro del ámbito local de un cierre a los que el código externo solo puede acceder o que solo puede cambiar mediante las operaciones que los exponen.
Un limitador ofrece una operación para permitir o rechazar mientras mantiene su contador interno used sin acceso directo.
Expresión de función
Una expresión de función crea una función como valor dentro de una expresión, por ejemplo, en el lado derecho de una asignación a una variable.
En const square = function (n) { return n * n; };, la expresión proporciona el valor almacenado en square.
Expresión de función con nombre
Una expresión de función con nombre crea una función con un nombre interno disponible dentro de su propio cuerpo, incluso para llamadas recursivas.
En const factorial = function fact(n) { /* body */ };, la variable externa es factorial y el nombre interno es fact.
Expresión de función invocada inmediatamente (IIFE)
Una expresión de función invocada inmediatamente, o IIFE, crea una función y la llama al instante, a menudo para dar a código antiguo un ámbito privado.
Los paréntesis finales de (function () { var hidden = 1; })(); invocan la función recién creada.

F

Fábrica de funciones
Una fábrica de funciones crea y devuelve funciones configuradas, usando el acceso de un cierre para conservar los argumentos o el estado local de su invocación.
Llamar a makeMultiplier(3) devuelve una función que recuerda 3 mientras acepta un número posterior que multiplicar.
Función
Una función es un conjunto reutilizable de instrucciones que realiza una tarea cuando se la llama y que, opcionalmente, acepta entradas y devuelve un resultado.
Un script llama a printHeading("Report") y printHeading("Totals") para reutilizar una misma rutina de encabezado.
Función anónima
Una función anónima es una expresión de función sin un nombre de función explícito, que a menudo se almacena en una variable o se pasa como argumento.
La expresión function (n) { return n * n; } no tiene un nombre de función interno en su sintaxis escrita.
Función de devolución de llamada
Una función de devolución de llamada es una función que se pasa como argumento para que una función receptora la invoque, y esta controla sus entradas y el uso de su retorno.
Una función auxiliar countIf llama a su función de devolución de llamada de comprobación para cada elemento y cuenta aquellos cuyos resultados son verdaderos en contexto booleano.
Función de devolución de llamada de transformación
Una función de devolución de llamada de transformación devuelve un valor de sustitución para un elemento de entrada, lo que permite que una función de transformación recopile las salidas en un array nuevo.
La función de devolución de llamada (n) => n * n convierte las entradas de [1, 2, 3] en sus cuadrados mediante una operación de transformación.
Función de devolución de llamada diferida
Una función de devolución de llamada diferida se programa para ejecutarse más tarde, mientras el código posterior a la llamada que la programa puede continuar sin esperar a que se ejecute.
Pasar sayHi a setTimeout permite que las sentencias siguientes se ejecuten antes de que aparezca el saludo programado.
Función de devolución de llamada síncrona
Una función de devolución de llamada síncrona se ejecuta durante la ejecución de la función receptora y termina su trabajo antes de que esta vuelva a quien la llamó.
Una función de devolución de llamada de map procesa las entradas del array antes de que la llamada a map terminada proporcione su array de resultado.
Función de orden superior
Una función de orden superior acepta una función como argumento, devuelve una función como resultado o combina ambas formas de tratar valores de función.
Los métodos de array aceptan funciones de devolución de llamada, mientras que una fábrica de multiplicadores devuelve una función de cálculo configurada.
Función definida en el punto de uso
Una función definida en el punto de uso es una expresión de función escrita directamente donde se necesita su valor, como una función flecha dentro de la lista de argumentos de una llamada.
La función flecha de repeat(3, (i) => console.log(i)) proporciona la acción sin una declaración con nombre separada.
Función envolvente
Una función envolvente es una función devuelta que añade comportamiento alrededor de una llamada a una función existente, a menudo transmitiendo sus entradas y conservando su resultado.
Una función envolvente de registro muestra los argumentos proporcionados, llama a la función original y después devuelve su resultado.
Función envolvente de ejecución única
Una función envolvente de ejecución única conserva un indicador de finalización y un primer resultado para que las llamadas posteriores puedan reutilizarlo sin repetir una operación completada.
Un indicador separado permite que una función envolvente de ejecución única recuerde que su primera llamada terminó incluso cuando el resultado fue 0.
Función flecha
Una función flecha es una expresión de función escrita con una flecha entre sus parámetros y su cuerpo, sin un enlace propio de this ni de arguments.
La función flecha (n) => n * 2 proporciona una breve función de devolución de llamada de transformación a un método de array como map.
Función pura
Una función pura calcula su salida únicamente a partir de sus argumentos y no hace cambios fuera de la llamada, incluida la salida a la consola.
Una función que solo devuelve n * 2 es pura; mostrar el producto introduciría un efecto secundario.

L

Literal de objeto
Un literal de objeto crea un objeto mediante llaves y propiedades con nombre; para devolverlo desde una función flecha concisa se encierra entre paréntesis.
La función flecha (n) => ({ value: n }) devuelve un objeto en lugar de tratar sus llaves como un bloque de sentencias.
Llamada a función
Una llamada a función invoca una función mediante paréntesis después de un valor de función, con los argumentos dentro de esos paréntesis.
Escribir sayHi() ejecuta su cuerpo, mientras que una línea que contiene solo sayHi lee el valor de la función.

M

Marco de pila
Un marco de pila contiene el estado de ejecución de una llamada a función activa, incluidos sus parámetros, variables locales y punto de continuación.
Dos llamadas recursivas activas pueden conservar cada una un valor distinto de n porque tienen marcos separados.
Modo estricto
El modo estricto es un modo de ejecución de JavaScript que rechaza la asignación a nombres no declarados y ayuda a evitar variables globales accidentales.
Comenzar un script normal con "use strict"; hace que una asignación count = 5; sin declaración genere un ReferenceError.
Mutación
La mutación cambia el contenido de un valor existente, como un array, y hace que el cambio sea visible mediante otras referencias a ese array.
Una función que llama a arr.push(3) modifica el mismo array que quien llama proporcionó como argumento.

N

Notación camelCase
La notación camelCase es un estilo de nombres con la primera palabra en minúscula y las siguientes con mayúscula inicial, usado habitualmente para nombres de funciones de JavaScript.
El nombre calculateTotal describe una acción y separa sus dos palabras sin espacios ni guiones bajos.

O

Objeto arguments
El objeto arguments es una colección similar a un array que contiene las entradas pasadas a una función ordinaria y se diferencia de un array real de parámetro de resto.
El código antiguo puede leer arguments[0], pero no puede llamar a arguments.map como método ordinario de array.

P

Parámetro
Un parámetro es un nombre local en la definición de una función que recibe el valor de un argumento cuando se llama a la función.
Los nombres width y height son parámetros en function area(width, height) { return width * height; }.
Parámetro de resto
Un parámetro de resto recopila los argumentos restantes de una llamada en un array real y aparece como último parámetro, precedido por tres puntos.
En function log(label, ...values) { /* body */ }, el primer argumento queda separado del array de resto.
Parámetro predeterminado
Un parámetro predeterminado usa una expresión especificada cuando su argumento es undefined, incluso cuando quien llama omite ese argumento.
El parámetro level = 50 conserva un 0 explícito, pero proporciona 50 cuando falta el argumento.
Pila de llamadas
La pila de llamadas registra las llamadas a funciones pendientes, coloca cada nueva invocación en la cima y elimina su marco cuando esa llamada termina.
Mientras sumOfSquares espera a square(3), la llamada a square tiene un marco por encima de la función que espera.
Predicado
Un predicado es una función de comprobación cuyo resultado determina si una entrada cumple una condición, utilizada por métodos como filter o find.
El predicado (n) => n > 4 selecciona qué números conserva un filtro sin cambiar por sí mismo sus valores.

R

Reasignación
La reasignación cambia el valor almacenado en una variable o parámetro existente, sin cambiar otra variable que contenía el valor anterior.
Dentro de una función, arr = [] cambia a qué apunta el parámetro sin sustituir la referencia al array de quien llama.
Recursión
La recursión ocurre cuando una función se llama a sí misma para resolver versiones más pequeñas de una tarea, con un caso de parada que no necesita otra llamada a sí misma.
Una función factorial multiplica su entrada por el resultado de la misma función con una entrada una unidad menor.
Referencia a función
Una referencia a función es un valor que identifica una función y permite que otra variable o función receptora llame más tarde a esa misma función.
Después de const alias = square;, llamar a alias(4) invoca la función a la que también se accede mediante square.
Retorno anticipado
Un retorno anticipado termina una llamada antes de que se ejecuten sus sentencias posteriores y suele manejar una entrada especial antes de que la función realice su trabajo principal.
Una función auxiliar de división puede devolver null para un divisor cero antes de que la ejecución llegue a la sentencia de división.

S

Sintaxis de propagación
La sintaxis de propagación expande las entradas de un array en argumentos de llamada separados, usando tres puntos antes de la expresión del array en la lista de argumentos.
Llamar a Math.max(...[3, 7, 2]) pasa tres números en lugar de pasar un array a Math.max.
Sombreado de variables
El sombreado de variables ocurre cuando una declaración interna oculta una declaración externa del mismo nombre dentro del ámbito interno, dando al nombre un enlace diferente.
Un parámetro llamado count oculta una count externa dentro de esa función sin cambiar el enlace externo.

T

Traza de la pila
Una traza de la pila enumera las llamadas activas cuando ocurrió un error, comenzando por la llamada más reciente y continuando con las llamadas que condujeron a ella.
Las entradas repetidas de una función recursiva pueden ayudar a localizar una condición de parada que la entrada nunca alcanza.

V

Valor de retorno
Un valor de retorno es el único valor producido por una llamada a función y proporcionado a quien llama para almacenarlo o usarlo en otra expresión.
Si double(5) devuelve 10, la expresión double(5) + 1 puede usar inmediatamente ese valor para producir 11.
Valor falso en contexto booleano
Un valor falso en contexto booleano se comporta como falso en una prueba de veracidad, por lo que un valor predeterminado antiguo con OR lógico puede sustituir entradas válidas como cero.
La expresión level || 50 sustituye 0, mientras que un valor predeterminado de parámetro conserva ese valor proporcionado.
Variable capturada
Una variable capturada es un enlace al que se accede mediante un cierre, de modo que la función puede leer su valor actual en lugar de una copia fija del momento de creación.
Cambiar una greeting externa de «Hi» a «Hello» cambia el valor que devuelve una llamada posterior a una función que lee greeting.
Variable local
Una variable local pertenece a un ámbito limitado de función o de bloque, lo que permite mantener sus datos de trabajo separados de datos externos con nombres similares.
Dos funciones independientes pueden usar cada una una total local sin que sus sumas se afecten entre sí.

Z

Zona muerta temporal
La zona muerta temporal es el intervalo anterior a la inicialización de un enlace let o const, durante el cual acceder a ese enlace genera un error de referencia.
Una lectura anticipada encuentra una variable local que oculta otra aunque todavía no esté inicializada, en lugar de usar un valor externo.

Sobre esta unidad

Por StudeliInformar de un error

Crea tus propios Materiales de Estudio

Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.

Comenzar