tipos orientado objetos lista funciones array alternativa javascript function-constructor

javascript - orientado - Usos legítimos del constructor de la función



lista de objetos javascript (7)

El único uso legítimo que he tenido es cuando escribí esto:

Function.prototype.New = (function () { var fs = []; return function () { var f = fs [arguments.length]; if (f) { return f.apply (this, arguments); } var argStrs = []; for (var i = 0; i < arguments.length; ++i) { argStrs.push ("a[" + i + "]"); } f = new Function ("var a=arguments;return new this(" + argStrs.join () + ");"); if (arguments.length < 100) { fs [arguments.length] = f; } return f.apply (this, arguments); }; }) ();

El código le permite usar Function.prototype.apply mientras ''usa'' la new palabra clave.

Ejemplo:

function Foo (x, y, z) { this.x = x; this.y = y; this.z = z; this.otherArgs = Array.prototype.slice.call (arguments, 3); } var foo = Function.prototype.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]); // /*equiv*/ var foo = Foo.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]); // /*equiv*/ var foo = Foo.New (1, 2, 3, 4, 5, 6, 7); var bool = true && foo.x == 1 && foo.y == 2 && foo.z == 3 && foo.otherArgs.length == 4 && foo.otherArgs [0] == 4 && foo.otherArgs [1] == 5 && foo.otherArgs [2] == 6 && foo.otherArgs [3] == 7 ; alert (bool);

Como se ha dicho en repetidas ocasiones, se considera una mala práctica utilizar el constructor de funciones (consulte también la especificación del lenguaje ECMAScript , edición, § 15.3.2.1):

new Function ([arg1[, arg2[, … argN]],] functionBody)

(donde todos los argumentos son cadenas que contienen nombres de argumento y la última (o única) cadena contiene el cuerpo de la función).

Para recapitular, se dice que es lento, como lo explica el equipo de Opera :

Cada vez que se llama al constructor de Function sobre una cadena que representa el código fuente, el motor de script debe iniciar la maquinaria que convierte el código fuente en código ejecutable. Esto suele ser costoso para el rendimiento, por ejemplo, cien veces más costoso que una simple llamada a función. (Marque ''Tarquin'' Wilton-Jones)

Aunque no es tan malo, según este post en MDC (aunque no lo probé usando la versión actual de Firefox).

Crockford adds que

[l] a cita de las convenciones del lenguaje hace que sea muy difícil expresar correctamente un cuerpo de función como una cadena. En el formato de cadena, no se puede hacer una verificación temprana de errores. [...] Y es un desperdicio de memoria porque cada función requiere su propia implementación independiente.

Otra diferencia es que

una función definida por un constructor de Función no hereda ningún ámbito que no sea el alcance global (que todas las funciones heredan). ( MDC )

Aparte de esto, debes estar atento para evitar la inyección de código malicioso cuando creas una new Function usando contenido dinámico.

Dicho eso, TJ Crowder dice en una respuesta que

[t] casi nunca hay ninguna necesidad de la nueva función [...] similar (...) tampoco, de nuevo, salvo algunos casos de borde avanzados.

Entonces, ahora me pregunto: ¿cuáles son estos "casos avanzados"? ¿Hay usos legítimos del constructor de funciones?


Es posible que desee ejecutar una cadena de código más de una vez. Usar el constructor de Funciones significa que solo tiene que compilarlo una vez.

Es posible que desee pasar argumentos al código, por ejemplo, si está rellenando un evento, puede recuperar el atributo de evento y construir una función esperando un argumento de evento.

Puede combinar los dos y compilarlo en una ubicación y ejecutarlo en otra y aún así administrar los argumentos en las variables que espera la cadena de código.


Este es un caso separado de mi otra respuesta.

Hace un tiempo utilicé el constructor de funciones para crear formateadores de cadenas personalizadas a los que se llamaba repetidamente. La sobrecarga de crear la función (que considero que es el problema de rendimiento del que está hablando) fue ampliamente superada por el rendimiento mejorado de las funciones personalizadas, que se crearon en tiempo de ejecución específicamente para procesar una cadena de formato en particular, y por lo tanto no necesitó evaluar toneladas de casos irrelevantes, o analizar una cadena de formato, para el caso. Es un poco como compilar una expresión regular, supongo.



Utilizo el new Function() constructor new Function() como un intérprete JS en línea en una de las aplicaciones web que estoy desarrollando:

function interpret(s) { //eval(s); <-- even worse practice try { var f = new Function(s); f(); } catch (err) { //graceful error handling in the case of malformed code } }

A medida que obtengo material en streaming sobre AJAX ( no un iframe), lo interpret() continuamente interpret() en readyStateChange == 3 . Esto funciona sorprendentemente bien.

Editar : aquí hay un caso de estudio claro que muestra que la new Function() es categóricamente más rápida que eval() . Es decir, nunca debería (¿raramente?) Usar eval en lugar de new Function() .

http://polyfx.com/stuff/bsort.html <- la versión de iteración 1000, puede bloquear su navegador

http://polyfx.com/stuff/bsort10.html <- la versión más corta

Eval es, en promedio, casi 8 veces más lento que la new Function() .


jQuery lo usa para analizar cadenas JSON cuando un objeto del analizador JSON no está disponible. Me parece legítimo :)

// Try to use the native JSON parser first return window.JSON && window.JSON.parse ? window.JSON.parse( data ) : (new Function("return " + data))();


NWMatcher - Selector y selector de CSS de Javascript, por Diego Perini - usa el constructor de Function ( 1 , 2 , 3 , 4 , etc.) para crear ("compilar") versiones altamente eficientes de selectores de selector.

El benchmark (que acabo de ejecutar en Chrome 5) habla por sí mismo:

Tenga en cuenta la diferencia entre NWMatcher y Sizzle, que es un motor de selección muy similar, solo que sin compilación de funciones :)

En una nota lateral, ECMAScript 5 no arroja ningún error en la invocación de la Function . Ni en modo estricto, ni en modos "estándar". El modo estricto, sin embargo, introduce algunas restricciones sobre la presencia de identificadores como "eval" y "argumentos":

  • No puede haber declarado variables / funciones / argumentos con tales nombres:

    function eval() { } var eval = { }; function f(eval) { } var o = { set f(eval){ } };

  • No puede asignar a dicho identificador:

    eval = { };

También tenga en cuenta que en modo estricto, la semántica eval es ligeramente diferente de la de ES3. El código de modo estricto no puede crear instancias de variables o funciones en el entorno desde el que se llamó:

eval('' "use strict"; var x = 1; ''); typeof x; // "undefined"