Objeto Función de JavaScript y Expresiones de Función con Nombre (NFE)
Aprende que las funciones de JavaScript son objetos: lee sus propiedades name y length, añade propiedades personalizadas y usa Expresiones de Función con Nombre (NFE) para autorreferencia fiable y recursión.
Las funciones son objetos
En JavaScript, toda función es un object. Este único hecho explica gran parte del comportamiento que de otro modo parece magia: puedes pasar una función como cualquier valor, almacenarla en una variable, leer propiedades de ella e incluso añadir tus propias propiedades.
Ya creas funciones constantemente con declaraciones y expresiones de función. Este capítulo analiza lo que es una función una vez que existe: un object con propiedades integradas útiles (name y length), la capacidad de contener propiedades personalizadas, y una forma especial — la Expresión de Función con Nombre — que permite a una función referirse a sí misma de manera fiable.
Esta página asume que te sientes cómodo con las Expresiones de Función. Si let f = function() {...} es nuevo para ti, léelo primero.
La propiedad name
Toda función tiene una propiedad name que contiene el nombre de la función como string. Lo inteligente es que JavaScript la rellena incluso cuando no hay un nombre en el lugar obvio — un comportamiento denominado nombramiento contextual.
El motor examina la asignación y copia el nombre de la variable en la función anónima. Esto también funciona con parámetros predeterminados y métodos de object:
Sin embargo, no existe magia que funcione siempre. Si no hay nombre ni nada de donde copiarlo — por ejemplo, una función creada dentro de un array — name es una string vacía:
La propiedad name es útil para el registro de logs y la depuración: un stack trace que dice at sayHi es mucho más útil que at <anonymous>.
La propiedad length
La propiedad length de una función devuelve el número de parámetros que declara en su definición. Los parámetros rest (...rest) y los parámetros con valores predeterminados no se cuentan, y el conteo se detiene en el primer parámetro de este tipo.
Un uso real habitual de length es inspeccionar un callback. Algunas bibliotecas llaman a un manejador de manera diferente según cuántos argumentos espera — por ejemplo, tratando a un manejador sin argumentos como "ejecutar una vez para todos" y a un manejador de un argumento como "ejecutar una vez por elemento".
Propiedades personalizadas
Dado que una función es un object, puedes añadirle tus propias propiedades. Esto es diferente a una variable local: una propiedad vive en la función y persiste entre llamadas, por lo que es una forma elegante de darle a una función su propio estado persistente.
Un ejemplo clásico es un contador de llamadas:
Una propiedad de función no es lo mismo que una variable dentro de la función. Una variable local se reinicia en cada llamada; una propiedad persiste, y también puede leerse y escribirse desde el exterior, lo que la hace útil para configuración (por ejemplo, almacenar en caché resultados en la propia función).
Expresiones de Función con Nombre (NFE)
Una Expresión de Función con Nombre es una expresión de función que lleva un nombre después de la palabra clave function:
let sayHi = function func(who) {
console.log("Hello, " + who);
};Esto parece inusual — ¿por qué dar un nombre a algo ya asignado a sayHi? El nombre func aquí es especial de dos maneras:
- Permite que la función se refiera a sí misma de manera fiable desde dentro de su propio cuerpo.
- Solo es visible dentro de la función — no puedes llamar a
func()desde fuera.
Por qué importa el nombre interno
Podrías pensar que simplemente podrías usar la variable exterior sayHi para la autorreferencia. El problema es que la variable exterior puede cambiar. Con una NFE, el nombre interno siempre apunta a la función actual, sin importar lo que le suceda a la variable:
Si la función hubiera llamado a sayHi("Guest") en lugar de func("Guest"), la llamada lanzaría un TypeError porque sayHi fue asignado a null. El nombre interno es inmune a eso.
NFE y recursión
Esta autorreferencia es exactamente lo que necesita la recursión. Una NFE mantiene el funcionamiento de una llamada recursiva incluso si la función es reasignada posteriormente o se pasa con otro nombre — consulta Recursión y pila en JavaScript para obtener el panorama completo.
Ten en cuenta que el truco del nombre interno se aplica solo a las Expresiones de Función. Una Declaración de Función no puede tener un nombre interno separado, y no tiene manera de ocultar un nombre del ámbito exterior, por lo que no puede mantener una autorreferencia privada de la misma manera.
Cuándo usar estas características
- Usa
namepara logs y salida de depuración más claros. - Usa
lengthal escribir bibliotecas que se adapten a la aridad de un callback. - Usa propiedades personalizadas para dar a una función estado persistente (contadores, cachés, configuración) sin necesidad de un cierre circundante o una variable global.
- Usa una Expresión de Función con Nombre siempre que una expresión de función deba llamarse a sí misma — especialmente para recursión o manejadores desvinculables — de modo que la llamada sobreviva a la reasignación de variables.
Resumen
Una función de JavaScript es un object que puedes inspeccionar y extender. La propiedad name proporciona su nombre (a menudo completado de forma contextual), length informa el número de parámetros declarados, y puedes añadir propiedades personalizadas para el estado persistente. Una Expresión de Función con Nombre añade un nombre exclusivamente interno que permite a una función llamarse a sí misma de manera fiable, lo cual es la forma más segura de escribir expresiones de función con autorreferencia y recursivas.