2010-09-26 20 views
8

hoy I've read we have a way of declaring the function by Function constructor. Pero nunca he visto la implementación real que usa el constructor Function en real. Entonces, me gustaría preguntar: ¿hay alguna circunstancia de que podamos obtener beneficio utilizando el constructor Function en lugar de usar la declaración function()? Y cuáles son las diferencias ocultas de entre (si hay alguna)Función constructor vs función declaración

Constructor Función

var func = new Function("x", "y", "return x*y;"); // pass the context by String 

función():?

var func = function(x, y){ return x*y; } 

Gracias

+2

Ver: [Usos legítimos del constructor de funciones] (http://stackoverflow.com/questions/3026089/legitimate-uses-of-the-function-constructor) – CMS

+1

Buen video sobre las funciones de JavaScript http: // developer. yahoo.com/yui/theater/video.php?v=crockonjs-3 – Thomas

+0

@CMS @Thomas, gracias por los enlaces. – c4il

Respuesta

10

El constructor de función es una forma de eval, que generalmente se debe evitar (es lenta y se considera insegura). Realmente no hay ningún beneficio al usar el constructor de funciones sobre la declaración de función incorporada a menos que desee construir una función a partir de componentes dinámicos, lo cual es bastante raro. Existen usos legítimos para este formulario, sin embargo, la mayoría de las veces se usa innecesariamente, por lo que se lo desprecia y generalmente se evita.

Además, las funciones creadas con el constructor de funciones no mantendrán una referencia al entorno en el que se definieron (el cierre). Cuando se ejecuten, extraerán esas variables directamente del alcance global.

var f, a; 
(function() { 
    var a = 123; 
    f = new Function("return a"); 
})(); 

f(); //undefined 

a = "global" 
f(); // "global" 

mientras que las funciones regulares hacer mantener una referencia al entorno en el que se definieron:

var f; 
(function() { 
    var a = 123; 
    f = function() { return a; } 
})(); 
f(); //123 
+0

Me pregunto qué estaban pensando cuando construyeron este objeto 'Function'. – Tarik

+0

Bueno, es bastante útil para algo así como la competencia js1k :-) – Pointy

+3

@Daniel, Tenga en cuenta que la parte "lenta" sería solo la función * compilación *, después de que se construye un objeto de función, se comportará exactamente igual que si fue creado con una 'FunctionDeclaration' o una' FunctionExpression'. – CMS

2

Bueno, La diferencia obvia al trabajar con cadenas es que tiene la opción de meta-programación, b y la construcción de la cadena en tiempo de ejecución (lo mismo que se podía hacer con eval). Sin embargo, esto tiene un doble filo, y podría conducir a una gama de otros problemas con la concatenación (inyección) literal, y tal vez simplemente complejidad. Si no tiene necesita la versión de cadena, no la usaría para ser honesto.

Una ventaja adicional de la versión normal (sin cadena) es que la mayoría de los minimizadores (u ofuscadores) de javascript sabrán qué hacer con ella. Esto parece improbable para la cadena, es decir, la dejarán "tal como está" (no minimizada u ofuscada).

+0

¿Puedes dar un ejemplo de metaprogramación de problemas? – Tarik

+1

@Braveyard - hecho * correcto * meta programación está bien; pero también es una gran manera de abrir los agujeros xss si se hace mal. Por ejemplo, si el usuario puede abusar de la cadena para que otros usuarios le publiquen sus cookies. –

2

Si está escribiendo un analizador de Javascript y está interpretando una cadena como una función, entonces podría usar un constructor de funciones. Por ejemplo, si se le da:

"function(x){return x+2}" 

Y usted tiene algún tipo de analizador léxico y se encuentra que es de hecho una subcadena función, para traducirlo a una función real que usaría new Function y añadirlo a su árbol.

De lo contrario, realmente no hay mucho que se me ocurra.

0

notas adicionales a la publicación Cristian Sánchez'.

Nunca se puede acceder a vars de ámbito local dentro de una 'Evaluación de funciones'.

Veamos la diferencia entre Function y eval.

función Ejemplo:

var f, a = 1; 
(function() { 
    var a = 123; 
    f = new Function("return a"); 
})(); 
console.log(f()) // 1 

la función de constructor no se sabe nada sobre el ámbito local, ya que crea un nuevo ámbito aislado debajo de la ventana/Objeto-mundial - no en la posición en la que es - esa es la principal diferencia para eval.

Eval-Ejemplo:

var f, a = 1; 
(function() { 
    var a = 123; 
    eval("f = function() { return a }"); 
})(); 
console.log(f()) // 123 

'eval' tiene acceso a los vars locales. Incluso si abarca todo el asunto.

var f, a = 1; 
(function() { 
    var a = 123; 
    eval("f = (function() { function f() { return a }; return f; })();"); 
})(); 
console.log(f()) // still 123 

En el siguiente ejemplo f() lanza un error - "a" no está definida en su propia (y global) alcance. El Function-Constructor tiene su propio alcance especial sin conocer nada fuera, excepto su ámbito principal, la ventana/global-object.

delete a; 
var f; 
(function() 
{ 
    var a = 1; 
    f = new Function("return a"); 
})(); 

console.log(f()); // Throws error (a is not defined) 

Si desea utilizar VARs locales, pasarlo como parámetros a la función constructor dentro del ámbito interno!

var f, a = 1; 
(function() { 
    var a = 123; 
    f = new Function("a", "return a"); 

    console.log(f(a)); // passing inner a: result = 123 
})(); 

console.log(f(a)); // passing outer a: result = 1 

o

var result, a = 1; 
(function() { 
    var a = 123; 
    var f = new Function("a", "return a"); 
    result = f(a); // store result in global var 
})(); 

console.log(result); // 123 

Puede ejecutar la función directamente con llamada/aplicarán, también (no "nueva" es necesario).

Function('a','b','c', 'console.log(c,b,a)').call(this, 1, 2, 3); // output: 3 2 1 
Function('console.log(arguments)').apply(this, [1, 2, 3]); // access through arguments[0-3] 

Por cierto, siempre recomiendan, estableciendo el modo estricto, para permitir el correcto comportamiento ES5.

Con el modo estricto, 'this' está (correctamente) indefinido por defecto, hasta que vincula un objeto.

Function('console.log(this)')(); // this is 'window' in sloppy mode 
Function('"use strict"; console.log(this)')(); // this is undefined - correct behavior 

Si lo desea, puede enlazar 'esto' explícitamente

// bind 'this' to 'window' again 
Function('"use strict";console.log(this)').bind(window)(); 
// bind 'this' to an Object without __proto__ 
Function('"use strict";console.log(this)').bind(Object.create(null))(); 

Por supuesto se puede enlazar cualquier/clase objeto de la función de ampliar los objetos.

function SomeClass() 
{ 
    this.a = 1; 
} 

var cls = new SomeClass(); 

new Function('"use strict"; this.a = 5; this.b = 6;').bind(cls)(); 

console.log(cls.a); // a = 5 - override property 
console.log(cls.b); // b = 6 - appended property 

Mismo resultado con llamada directa, sin palabra clave 'nueva'.

function SomeClass() 
{ 
    this.a = 1; 
} 

var cls = new SomeClass(); 

Function('"use strict"; this.a = 5; this.b = 6; this.foo = function(){console.log("bar")}').call(cls); 

console.log(cls.a); // a = 5 - override property 
console.log(cls.b); // b = 6 - appended property 
console.log(cls.foo()); // bar - appended function 

Cada función/clase se crea mediante el constructor de 'Funciones'.

Así que no tiene que escribir "Función" en su código. También puedes usar el constructor-object.

function SomeClass() 
{ 
    this.a = 1; 
} 

var cls = new SomeClass(); 

SomeClass.constructor("this.a = 2;").call(cls); 

cls; // SomeClass {a: 2}, because "SomeClass.constructor" === Function 

El uso de 'Función' es positivo, por ejemplo para los juegos, si usted tiene un XMLHttpRequest-Precargador, que carga una gran Javascript-File (5-10 MB scripts de paquetes), mientras que usted quiere mostrar una barra de carga u otra cosa para el usuario, en su lugar carga todo con una secuencia de comandos, mientras que el usuario está esperando cargar la página sin ninguna respuesta visual.

No importa si carga una secuencia de comandos grande mediante una etiqueta de secuencia de comandos o mediante una función una vez al inicio. El motor tiene que cargar el código simple y evaluarlo de cualquier manera. No hay aspectos de seguridad, si su (!) Código proviene de una fuente confiable (su dominio) y usted sabe qué hay dentro.

'Función' y 'eval' solo son incorrectos con código no confiable (cuando otros usuarios influyen en él) o en bucles (lenta ejecución debido a compilación), pero está bien cargar & evaluar sus propios scripts al inicio , si el código es el mismo que en los archivos Javascript externos.

Cuestiones relacionadas