Hay una forma más de crear una función. Rara vez se utiliza, pero a veces no queda otra alternativa.
La sintaxis para crear una función:
let func = nueva Función ([arg1, arg2, ...argN], functionBody);
La función se crea con los argumentos arg1...argN
y la functionBody
dada.
Es más fácil de entender mirando un ejemplo. Aquí hay una función con dos argumentos:
let suma = nueva Función('a', 'b', 'devolver a + b'); alerta( suma(1, 2) ); // 3
Y aquí hay una función sin argumentos, con solo el cuerpo de la función:
let sayHola = new Function('alert("Hola")'); decir Hola(); // Hola
La principal diferencia con otras formas que hemos visto es que la función se crea literalmente a partir de una cadena, que se pasa en tiempo de ejecución.
Todas las declaraciones anteriores requerían que nosotros, los programadores, escribiéramos el código de función en el script.
Pero new Function
permite convertir cualquier cadena en una función. Por ejemplo, podemos recibir una nueva función de un servidor y luego ejecutarla:
let str =... recibir el código de un servidor dinámicamente... let func = nueva función (cadena); función();
Se utiliza en casos muy específicos, como cuando recibimos código de un servidor, o para compilar dinámicamente una función a partir de una plantilla, en aplicaciones web complejas.
Por lo general, una función recuerda dónde nació en la propiedad especial [[Environment]]
. Hace referencia al entorno léxico desde donde se crea (lo cubrimos en el capítulo Alcance variable, cierre).
Pero cuando se crea una función usando new Function
, su [[Environment]]
se configura para hacer referencia no al entorno léxico actual, sino al global.
Entonces, dicha función no tiene acceso a variables externas, solo a las globales.
función obtenerFunc() { let valor = "prueba"; let func = new Function('alerta(valor)'); función de retorno; } getFunc()(); // error: el valor no está definido
Compárelo con el comportamiento habitual:
función obtenerFunc() { let valor = "prueba"; let func = función() { alerta(valor); }; función de retorno; } getFunc()(); // "prueba", del entorno léxico de getFunc
Esta característica especial de new Function
parece extraña, pero parece muy útil en la práctica.
Imaginemos que debemos crear una función a partir de una cadena. El código de esa función no se conoce al momento de escribir el script (es por eso que no usamos funciones regulares), pero se conocerá en el proceso de ejecución. Podemos recibirlo del servidor o de otra fuente.
Nuestra nueva función necesita interactuar con el script principal.
¿Qué pasaría si pudiera acceder a las variables externas?
El problema es que antes de publicar JavaScript en producción, se comprime usando un minificador , un programa especial que reduce el código eliminando comentarios y espacios adicionales y, lo que es importante, cambia el nombre de las variables locales a otras más cortas.
Por ejemplo, si una función tiene let userName
, minifier la reemplaza con let a
(u otra letra si ésta está ocupada) y lo hace en todas partes. Por lo general, esto es algo seguro, porque la variable es local, nada fuera de la función puede acceder a ella. Y dentro de la función, minifier reemplaza cada mención de la misma. Los minificadores son inteligentes, analizan la estructura del código para no romper nada. No son sólo una tonta búsqueda y reemplazo.
Entonces, si new Function
tuviera acceso a variables externas, no podría encontrar userName
renombrado.
Si new Function
tuviera acceso a variables externas, tendría problemas con los minificadores.
Además, dicho código sería arquitectónicamente malo y propenso a errores.
Para pasar algo a una función, creada como new Function
, debemos usar sus argumentos.
La sintaxis:
let func = nueva Función ([arg1, arg2, ...argN], functionBody);
Por razones históricas, los argumentos también se pueden dar como una lista separada por comas.
Estas tres declaraciones significan lo mismo:
nueva Función('a', 'b', 'devolver a + b'); // sintaxis básica nueva Función('a,b', 'devolver a + b'); // separados por comas nueva Función('a, b', 'devolver a + b'); // separados por comas con espacios
Las funciones creadas con new Function
tienen [[Environment]]
que hace referencia al entorno léxico global, no al externo. Por lo tanto, no pueden utilizar variables externas. Pero eso es realmente bueno, porque nos protege contra errores. Pasar parámetros explícitamente es un método mucho mejor desde el punto de vista arquitectónico y no causa problemas con los minificadores.