2011-01-05 20 views
68

¿Estas dos funciones están haciendo lo mismo detrás de escena? (en funciones de extracto único)¿Son eval() y new Function() lo mismo?

var evaluate = function(string) { 
    return eval('(' + string + ')'); 
} 

var func = function(string) { 
    return (new Function('return (' + string + ')')()); 
} 

console.log(evaluate('2 + 1')); 
console.log(func('2 + 1')); 
+2

De hecho, esto se usa en jQuery 1.7.2 línea 573. Aunque con "algunos controles de seguridad" – PicoCreator

+0

¿Por qué se considera 'nuevo' en esta discusión? 'Función' ejemplifica implícitamente un' objeto de función'. Excluir 'new' no cambiará el código en absoluto. Aquí hay una jsfiddle que demuestra que: http://jsfiddle.net/PcfG8/ –

Respuesta

87

No, son no lo mismo.

  • eval() evalúa una cadena como una expresión de JavaScript dentro del alcance de ejecución actual y puede acceder a las variables locales.
  • new Function() analiza el código de JavaScript almacenado en una cadena en un objeto de función, que luego se puede llamar. No puede acceder a las variables locales porque el código se ejecuta en un ámbito separado.

consideran este código:

function test1() { 
    var a = 11; 
    eval('(a = 22)'); 
    alert(a);   // alerts 22 
} 

Si se utilizaron new Function('return (a = 22);')(), la variable local a conservaría su valor. Sin embargo, algunos programadores de JavaScript como Douglas Crockford creen que neither should be used a menos que absolutely necessary, y la evaluación/uso del constructor Function en datos no confiables es inseguro e imprudente.

+5

"nunca se debe usar" es una afirmación tan amplia. Qué tal, nunca se debe usar cuando alguna de las entradas está fuera de tu control. Habiendo dicho eso, nunca tuve que usarlo, excepto para analizar JSON. Pero he respondido preguntas aquí que parecían usos válidos, implicaba algo como permitir que los administradores generen funciones de plantilla que los usuarios finales podrían usar. En este caso, la entrada fue generada por un administrador, por lo que era aceptable –

+1

@Juan: El argumento de Crockford es que eval se usa mal a menudo (depende de su perspectiva), por lo que debe excluirse de un JavaScript de "mejores prácticas".Sin embargo, estoy de acuerdo en que es útil para usos como el análisis sintáctico de expresiones JSON o aritméticas cuando la entrada se valida por primera vez. Incluso Crockford lo usa en su biblioteca JSON json2.js. – PleaseStand

+0

¿Significa esto que 'new Function (code)' es lo mismo que 'eval ('(function() {' + code + '})()')' o es un contexto de ejecución completamente nuevo? –

1

En ese ejemplo, los resultados son los mismos, sí. Ambos ejecutan la expresión que pasas. Esto es lo que los hace tan peligrosos.

Pero hacen cosas diferentes detrás del escenario. El que implica new Function(), entre bastidores, crea una función anónima a partir del código que usted suministra, que se ejecuta cuando se invoca la función.

El JavaScript que le pasa no se ejecuta técnicamente hasta que invoca la función anónima. Esto está en contraste con eval() que ejecuta el código de inmediato y no genera una función basada en él.

+0

¿Puedes exponer un poco más? ¿No están ambos ejecutados en la declaración de devolución? ¿La función() usa otro nivel de llamada de pila que eval? – qwertymk

+0

'¿La función() usa otro nivel de llamada de pila que eval?': Supongo que sí, porque 'eval()' no crea una función a partir de su entrada, solo la ejecuta. 'new Function()' crea una nueva función, que luego invoca. –

+0

@SimpleCoder: Function() no agrega nada a la pila de llamadas. Solo si llamas a la función resultante. eval hace exactamente lo mismo (si se aplica en el contexto de la pregunta) –

2

Si quiere decir, ¿dará los mismos resultados, entonces sí ... pero solo para evaluar (también conocido como "evaluar esta cadena de JavaScript") sería mucho más simple.

EDITAR continuación:

es como decir ... son estos dos problemas de matemáticas de la misma:

1 + 1

1 + 1 + 1 - 1 + 1 - 1 * 1/1

+0

¿ambos re-analizan la cadena? – qwertymk

+0

ambos analizarán la cadena (en su ejemplo de código). no sé a qué te refieres con "re-analizar". –

+1

Estoy seguro de que ambos analizan (evalúan) la cadena en algún momento, pero el objeto 'Function' probablemente almacena la cadena en una variable miembro privada en' eval' cuando invoca la función. – palswim

6

En su actualización, las llamadas a evaluate y func producen el mismo resultado. Pero, definitivamente no están "haciendo lo mismo detrás de escena". La función func crea una nueva función, pero luego la ejecuta de inmediato, mientras que la función evaluate simplemente ejecuta el código in situ.

A partir de la pregunta original:

var evaluate = function(string) { 
    return eval(string); 
} 
var func = function(string) { 
    return (new Function('return (' + string + ')')()); 
} 

Estos le darán resultados muy diferentes:

evaluate('0) + (4'); 
func('0) + (4'); 
+0

En cualquier caso, ambas son malas prácticas en todos los casos, excepto en los más excepcionales. – palswim

+5

Bueno, modificó su ejemplo de acuerdo con su implementación. Si hubiera implementado evaluar como 'return eval ('(' + string + ')');' entonces arrojarían los mismos resultados. –

+0

@Juan No pensé pero sí. Editado la pregunta – qwertymk

6

new Function crea una función que puede ser reutilizado. eval simplemente ejecuta la cadena dada y devuelve el resultado de la última instrucción. Su pregunta está equivocada ya que intentó crear una función contenedora que utiliza la Función para emular una evaluación.

¿Es verdad que comparten algún código detrás de las cortinas? Sí, muy probablemente Exactamente el mismo código? No, ciertamente

Por diversión, esta es mi propia implementación imperfecta usando eval para crear una función. Espero que arroje algo de luz en la diferencia!

function makeFunction() { 
    var params = []; 
    for (var i = 0; i < arguments.length - 1; i++) { 
    params.push(arguments[i]); 
    } 
    var code = arguments[arguments.length - 1]; 


// Creates the anonymous function to be returned 
// The following line doesn't work in IE 
// return eval('(function (' + params.join(',')+ '){' + code + '})'); 
// This does though 
return eval('[function (' + params.join(',')+ '){' + code + '}][0]'); 
} 

La mayor diferencia entre esta y la nueva función es que la función no tiene un alcance léxico. Entonces no tendría acceso a las variables de cierre y la mía lo haría.

+0

¿por qué no utilizar 'arguments.slice()' en lugar del ciclo for? O si los argumentos no son una verdadera matriz, '[] .slice.call (arguments, 1)'. – Xeoncross

1

Sólo quiero señalar algunas sintaxis utilizada en los ejemplos aquí y lo que significa:

var func = function(string) { 
    return (new Function('return (' + string + ')')()); 
} 

aviso de que la función (...)() tiene el "()" al final. Esta sintaxis causará func para ejecutar la nueva función y devolver la cadena no una función que devuelve la cadena, pero si se utiliza la siguiente:

var func = function(string) { 
    return (new Function('return (' + string + ')')); 
} 

Ahora func devolverá una función que devuelve una cadena.

Cuestiones relacionadas