2011-01-05 8 views
68

Queste due funzioni fanno la stessa cosa dietro le quinte? (nelle funzioni a singola istruzione)Eval() e new Function() sono la stessa cosa?

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

In realtà questo viene utilizzato in jQuery 1.7.2 riga 573. Anche se con "alcuni controlli di sicurezza" – PicoCreator

+0

Perché in questa discussione viene considerato 'nuovo'? 'Function' istanzia implicitamente un' oggetto funzione'. Escludendo 'new' non cambierà affatto il codice. Ecco un jsfiddle che lo dimostra: http://jsfiddle.net/PcfG8/ –

risposta

87

No, sono non lo stesso.

  • eval() valuta una stringa come un'espressione JavaScript nell'ambito corrente di esecuzione e può accedere alle variabili locali.
  • new Function() analizza il codice JavaScript memorizzato in una stringa in un oggetto funzione, che può quindi essere chiamato. Non può accedere alle variabili locali perché il codice viene eseguito in un ambito separato.

Considerate questo codice:

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

Se new Function('return (a = 22);')() sono stati utilizzati, la variabile locale a avrebbe mantenuto il suo valore. Ciononostante, alcuni programmatori JavaScript come Douglas Crockford ritengono che neither should be used a meno che non sia absolutely necessary e la valutazione/utilizzo del costruttore Function su dati non attendibili non siano sicuri e imprudenti.

+5

"non dovrebbe mai essere usato" è una dichiarazione così ampia. Che ne dici, non dovrebbe mai essere usato quando uno degli input è fuori dal tuo controllo. Detto questo, non ho mai avuto bisogno di usarlo, tranne per l'analisi di JSON. Ma ho qui risposto a domande che mi sembravano usi validi, implicava qualcosa come permettere agli amministratori di generare funzioni di template che gli utenti finali potevano usare. In questo caso l'input è stato generato da un amministratore, quindi è stato accettabile –

+1

@Juan: il punto di Crockford è che l'eval viene spesso utilizzato in modo improprio (dipende dalla tua prospettiva), quindi dovrebbe essere escluso da un "best practice" JavaScript.Sono d'accordo, tuttavia, che è utile per tali usi come l'analisi di espressioni JSON o aritmetiche quando l'input viene prima correttamente validato. Persino Crockford lo usa nella sua libreria JSON json2.js. – PleaseStand

+0

Questo significa che 'new Function (code)' è uguale a 'eval ('(function() {' + code + '})()')' o è un contesto di esecuzione completamente nuovo? –

1

In questo esempio, i risultati sono gli stessi, sì. Entrambi eseguono l'espressione che passi. Questo è ciò che li rende così pericolosi.

Ma fanno cose diverse dietro al profumo. Quella che coinvolge new Function(), dietro le quinte, crea una funzione anonima dal codice che fornisci, che viene eseguita quando viene invocata la funzione.

Il codice JavaScript che si passa ad esso non viene eseguito tecnicamente finché non si richiama la funzione anonima. Questo è in contrasto con eval() che esegue immediatamente il codice e non genera una funzione basata su di esso.

+0

Puoi esporre un po 'di più? Non sono entrambi eseguiti nella dichiarazione di ritorno? La Funzione() usa un altro livello di chiamata stack rispetto a eval? – qwertymk

+0

'La Funzione() usa un altro livello di chiamata di stack di eval?': Io presumo di sì, perché 'eval()' non crea una funzione dal tuo input, ma semplicemente la esegue. 'new Function()' crea una nuova funzione, che quindi invoca. –

+0

@SimpleCoder: Function() non aggiunge nulla allo stack di chiamate. Solo se chiami la funzione risultante. eval fa esattamente la stessa cosa (se applicato nel contesto della domanda) –

2

Se si intende, otterrà gli stessi risultati, quindi sì ... ma solo per eval (ovvero "valutare questa stringa di JavaScript") sarebbe molto più semplice.

Modifica Qui di seguito:

E 'come dire ... sono questi due problemi di matematica lo stesso:

1 + 1

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

+0

entrambi riesaminano la stringa? – qwertymk

+0

entrambi analizzeranno la stringa (nell'esempio di codice). non so cosa intendi per "ri-analizzare". –

+1

Sono sicuro che entrambi analizzino (valutano) la stringa a un certo punto, ma l'oggetto 'Function' probabilmente memorizza la stringa in una variabile membro privata su' eval' quando invochi la funzione. – palswim

6

No.

Nel suo aggiornamento, le chiamate a evaluate e func producono lo stesso risultato. Ma sicuramente non stanno "facendo la stessa cosa dietro le quinte". La funzione func crea una nuova funzione, ma immediatamente la esegue, mentre la funzione evaluate esegue semplicemente il codice sul posto.

Dalla domanda iniziale:

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

Questi vi darà risultati molto diversi:

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

In ogni caso, entrambe sono pratiche sbagliate in tutti i casi tranne i più eccezionali. – palswim

+5

Bene, hai corretto il tuo esempio in base alla sua implementazione. Aveva implementato valutare come 'return eval ('(' + string + ')');' quindi avrebbero dato gli stessi risultati. –

+0

@Juan Non ci ho pensato ma si. Modificata la domanda – qwertymk

6

new Function crea una funzione che può essere riutilizzato. eval esegue semplicemente la stringa data e restituisce il risultato dell'ultima istruzione. La tua domanda è fuorviante mentre tentavi di creare una funzione wrapper che utilizza Function per emulare un'eval.

È vero che condividono qualche codice dietro le tende? Sì, molto probabilmente. Esattamente lo stesso codice? No, certamente.

Per divertimento, ecco la mia implementazione imperfetta utilizzando eval per creare una funzione. Spero che faccia luce nella differenza!

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 più grande differenza tra questa e la nuova funzione è che la funzione non è in ambito lessicale. Quindi non avrebbe accesso alle variabili di chiusura e il mio lo farebbe.

+0

perché non usare 'arguments.slice()' al posto del ciclo for? O se gli argomenti non sono un vero array, '[] .slice.call (argomenti, 1)'. – Xeoncross

1

Voglio solo sottolineare alcune sintassi utilizzata negli esempi qui e che cosa significa:

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

noti che la funzione (...)() ha il "()" alla fine. Questa sintassi causerà func per eseguire la nuova funzione e restituire la stringa non è una funzione che restituisce stringa, ma se si utilizza il seguente:

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

Ora func restituirà una funzione che restituisce una stringa.

Problemi correlati