W3docs

Sintaxis de Funciones en JavaScript

Aprende la sintaxis "new Function" en JavaScript: cómo crear funciones desde strings en tiempo de ejecución, reglas de ámbito, diferencias con eval y cuándo usarla.

La mayoría de las veces creas una función con una declaración, una expresión o una función flecha. Pero JavaScript tiene una forma más: el constructor new Function, que construye una función a partir de strings en tiempo de ejecución. Esta página se centra en esa sintaxis: su forma exacta, las reglas de ámbito que sorprenden a la mayoría de los desarrolladores, cómo se compara con eval y los pocos casos en los que es la herramienta adecuada.

La sintaxis new Function

La sintaxis new Function te permite crear una función cuyos parámetros y cuerpo se proporcionan como strings. Como el cuerpo es solo texto hasta que el motor lo analiza, puedes ensamblar una función cuyo código no se conoce cuando escribes tu programa, sino en el momento en que se ejecuta.

La forma general es:

let func = new Function([arg1, arg2, ...argN], functionBody);

Cada argumento es un string. Los primeros argumentos nombran los parámetros; el último argumento es siempre el cuerpo de la función.

javascript— editable

Puedes pasar todos los nombres de parámetros en un único string separado por comas, lo cual es equivalente:

javascript— editable

La palabra clave new es opcional aquí — Function('a', 'b', 'return a + b') produce el mismo resultado — pero escribir new Function(...) es la forma convencional y más clara.

Por qué existe

Lo principal que hace diferente a new Function de una declaración normal es que el cuerpo proviene de un string. Ese string puede recibirse desde cualquier lugar: una respuesta del servidor, una plantilla, configuración del usuario o texto que construyes en tiempo de ejecución. Por eso existe esta sintaxis: exactamente para los casos en que el código que quieres ejecutar no existe aún cuando escribes el programa.

Ámbito: la gran trampa

Este es el detalle que confunde a todos. Una función creada con new Function no captura el ámbito donde fue creada. A diferencia de un closure normal, su entorno léxico externo es el ámbito global, no el local.

function makeAdder() {
  let outer = 100;
  // This function tries to read `outer`...
  return new Function('x', 'return x + outer');
}

const add = makeAdder();
add(5); // ReferenceError: outer is not defined

Una función normal escrita de la misma manera cerraría felizmente sobre outer. La versión con new Function no puede — solo ve sus propios parámetros y el ámbito global:

javascript— editable

Esto es intencional. Si new Function pudiera acceder a las variables locales, los minificadores (que renombran outer a a, secret a b, etc.) romperían cualquier código que referenciara esos nombres como strings. Al restringir el acceso al ámbito global, el lenguaje mantiene la minificación segura. La conclusión práctica: pasa todo lo que una función dinámica necesite a través de sus argumentos, nunca esperes que lea variables del entorno circundante.

Propiedades de una función dinámica

Una función construida de esta manera es un objeto función normal en todos los demás aspectos, con una peculiaridad: su name siempre es "anonymous":

javascript— editable

Ese nombre vacío es una de las razones por las que las funciones dinámicas son más difíciles de leer en los stack traces — consulta la nota de depuración a continuación.

new Function vs. eval

Tanto new Function como eval convierten strings en código ejecutable, pero se comportan de manera muy diferente:

  • eval(str) ejecuta str en el ámbito actual, por lo que puede leer e incluso modificar variables locales cercanas. Ese acoplamiento estrecho lo hace más difícil de optimizar y más fácil de usar mal.
  • new Function está aislada del ámbito local (como se mostró arriba) y te devuelve una función reutilizable en lugar de una evaluación de un solo uso.

Para el raro caso en que genuinamente necesites ejecutar código desde un string, new Function es la más segura de las dos porque su radio de acción se limita al ámbito global y sus parámetros explícitos.

Aplicaciones prácticas y ejemplos

A continuación encontrarás un ejemplo completo y ejecutable que puedes editar y ejecutar en el navegador.

"Pruébalo tú mismo" no está disponible para este ejemplo.

Perspectivas avanzadas sobre la creación dinámica de funciones

La creación dinámica de funciones en JavaScript, facilitada por la sintaxis new Function, es una técnica poderosa que permite a los desarrolladores construir funciones a partir de strings de código en tiempo de ejecución. Esta capacidad es especialmente útil en escenarios donde el código a ejecutar no es estático ni se conoce de antemano, como en aplicaciones que requieren un alto grado de flexibilidad o en situaciones donde los scripts se generan o modifican dinámicamente. En esta sección, profundizaremos en los mecanismos, beneficios y consideraciones de la creación dinámica de funciones, ofreciendo una comprensión más rica y ejemplos prácticos para ilustrar su potencial.

Mecánica de la creación dinámica de funciones

La sintaxis new Function crea una nueva instancia de función. Los argumentos del constructor new Function son strings que representan los argumentos de la función, seguidos de un string que representa el cuerpo de la función.

javascript— editable

Esto equivale funcionalmente a declarar una función de la manera tradicional, pero con la diferencia clave de poder ensamblar el código de la función dinámicamente, en tiempo de ejecución.

Beneficios de la creación dinámica de funciones

  1. Flexibilidad y personalización: La creación dinámica de funciones permite un alto grado de personalización, ya que las funciones pueden generarse en función de la entrada del usuario, ajustes de configuración u otros datos en tiempo de ejecución.
  2. Scripting y plantillas: Es especialmente útil para implementar soluciones de scripting personalizadas o motores de plantillas donde la lógica de la plantilla necesita evaluarse en tiempo de ejecución.
  3. Aislamiento y seguridad: Cuando se usa con cuidado, puede ejecutar código en un entorno más controlado, aislando potencialmente el código ejecutado dinámicamente del contexto principal de la aplicación.

Consideraciones y buenas prácticas

Aunque la creación dinámica de funciones es poderosa, conlleva sus propias consideraciones:

  1. Seguridad: La preocupación principal es la seguridad. Dado que el código de la función se construye a partir de strings, existe el riesgo de ejecutar código malicioso si la entrada no se sanitiza correctamente. Valida y sanitiza siempre la entrada que se usará para generar código de función.
  2. Rendimiento: Las funciones creadas dinámicamente pueden ser menos eficientes que sus equivalentes declarados estáticamente, ya que el motor de JavaScript debe analizar el string del cuerpo de la función cada vez que se crea una nueva función. Utiliza esta característica con prudencia, especialmente en rutas críticas de rendimiento.
  3. Depuración: Depurar funciones generadas dinámicamente puede ser más difícil, ya que el código no existe hasta el tiempo de ejecución. Proporcionar nombres significativos a las funciones creadas dinámicamente puede ayudar a mitigar este problema.
  4. Limitación del ámbito léxico: Las funciones creadas con new Function no capturan el ámbito local donde se definen. Solo tienen acceso a las variables globales y a sus propios parámetros. Esto puede provocar ReferenceErrors si esperas que accedan a variables externas. (Consulta la sección Ámbito arriba; pasa los datos a través de argumentos.)

Ejemplo avanzado: un motor de plantillas simple

Para ilustrar el uso práctico de la creación dinámica de funciones, considera la implementación de un motor de plantillas simple. Este motor reemplazará marcadores de posición en un string de plantilla con valores de un objeto de datos — y, crucialmente, los datos se pasan como argumento, resolviendo la limitación del ámbito.

javascript— editable

Nota: La secuencia \${ escapa la sintaxis del template literal. Esto evita que el marcador ${expr} se evalúe inmediatamente, asegurando que se pase como string literal al cuerpo de la función generada.

Este ejemplo demuestra no solo la flexibilidad que ofrece la creación dinámica de funciones, sino que también destaca la importancia de una construcción y sanitización cuidadosa de la entrada para evitar riesgos de seguridad.

Resumen

El constructor new Function construye una función a partir de strings en tiempo de ejecución:

let func = new Function([arg1, ..., argN], functionBody);

Puntos clave a recordar:

  • El último argumento es siempre el cuerpo de la función; los anteriores nombran los parámetros.
  • El ámbito externo de una función creada dinámicamente es global, no el lugar donde fue creada — no puede cerrar sobre variables locales, así que pasa los datos a través de argumentos.
  • Generalmente es más segura que eval (que se ejecuta en el ámbito actual), pero ambas evalúan strings, así que aliméntala únicamente con entrada confiable y sanitizada.
  • Úsala para código genuinamente dinámico — motores de plantillas, evaluadores de expresiones en sandbox, handlers generados en tiempo de ejecución — y prefiere funciones ordinarias o funciones flecha en todos los demás casos.

Para profundizar en temas relacionados, consulta JavaScript Closures, Ámbito de variables y Expresiones de función.

Práctica

Práctica
¿Cuáles son las características y buenas prácticas asociadas con la nueva sintaxis de función en JavaScript?
¿Cuáles son las características y buenas prácticas asociadas con la nueva sintaxis de función en JavaScript?
Was this page helpful?