2010-04-02 22 views
8

Per esempio:Come sovrascrivere la funzione eval in javascript?

(function() { 
     var proxied = window.eval; 
     window.eval = function() { 
     return proxied.apply(this, arguments); 
     }; 
    })(); 

Ma questo codice non funziona.

+17

mi spaventa un po 'a chiedersi perché si potrebbe fare questo ... – Paddy

+0

Stranamente ... Perché "allerta" e altre funzioni è prevalente. – ko1ik

+2

Qual è il tuo caso d'uso? –

risposta

8

Non è possibile. (c'è una limitata modo di farlo, ma è piuttosto limitata e non mantiene la magia che bobince talks about.)

eval non è una vera e propria funzione JavaScript in almeno una importante implementazione (JScript di IE , almeno non tramite IE7, non ho testato la nuova versione di IE8), quindi a prima vista ti troverai nei guai, perché non sarai in grado di chiamare l'originale tramite apply (non è quello che conta davvero per eval).

La recente specifica ECMAScript 5 non consente specificamente prioritario eval in modalità rigorosa (non che si sta utilizzando modalità rigorosa lì), che mi fa sospettare che ci sono ottimi motivi per non imperativi esso.

+2

La modalità Rigorosa disabilita l'aliasing/override di 'eval' perché l'interprete non sarebbe mai in grado di dire in anticipo che un blocco funzione non contiene usi nascosti di' eval'. Se un terp (specialmente JIT) può essere sicuro che una funzione contiene solo codice semplice e nessuna valutazione, esiste una gamma molto più ampia di ottimizzazioni che può eseguire sul codice generato. – bobince

+0

@bobince: Grazie, buono a sapersi. –

+0

Uso eval per componenti di costruzione dinamica di ExtJs. . Esempio: Ext.data.Connection() richiesta ({ ... , il successo: la funzione (risposta, opta) { \t eval (response.responseText); \t}} ) componenti sono memorizzati su il server. Questo utilizzo in diversi progetti. Nell'un progetto il valore di ritorno da "eval" viene utilizzato come parametro in entrata per un metodo globale, l'altro - non si utilizza. Ho bisogno di questo codice per mantenere la funzionalità. – ko1ik

0

Non solo non dovresti farlo, ma penso anche che probabilmente non puoi. Innanzitutto, eval è una funzione globale, e come tale non è un membro della finestra (come hai provato sopra). In secondo luogo, come funzione globale, è altamente probabile che sia cablato nella VM e non possa essere sovrascritto.

+2

In realtà, sia la 3a edizione spec (1999) che la 5a edizione spec (2010) la chiamano come una proprietà dell'oggetto globale (che è 'finestra' nei browser), nella sezione 15.1.2.1. Ma è vero che non è * implementato in modo affidabile * in questo modo. –

+0

TJ ha ragione, tutte le variabili globali sono proprietà dell'oggetto window. Inoltre, collegato alla VM? Non esiste una VM, javascript non viene compilato in alcun codice byte VM. Infine, puoi sovrascrivere la maggior parte delle funzioni o delle proprietà globali, l'eval è solo speciale. –

+0

"Non c'è una VM" - questo è abbastanza scorretto. Molti browser noi VM JS guardiamo a TraceMonkey (firefox) o V8 (chrome), quali sono quelli? Non sono interpeters poiché compilano il codice JS al codice macchina. Ma non sono tecnicamente compilatori poiché non espongono l'intera macchina. Esporre un sottoinsieme (macchina virtuale) al codice. se quella non è una VM ... che diamine è? "Eval è solo speciale" - ah quindi avevo ragione. –

10

eval è magico. A differenza di una funzione di 'reale', è in grado di leggere e scrivere le variabili locali nel chiamante:

function foo() { 
    var a= 1; 
    eval('a+= 1'); 
    alert(a); // 2 
} 

sostituirlo eval con una funzione di proxy e hai un problema: il a+= 1 esegue nel campo di applicazione della funzione di proxied invece di foo. A seconda di ciò che sta accadendo nel codice evaled che potrebbe causare la perdita dei valori, il danneggiamento delle globali locali accidentali del proxy e così via.

È pertanto impossibile sostituire eval con un proxy completamente funzionante. (Per casi semplici che non hanno bisogno della gente del posto, è possibile farla franca.)

+0

Re "impossibile", è possibile sostituire eval con un proxy completamente funzionante 'MyEval', ma è necessario eval ---' MyEval (_ => eval (_)) ' – Pacerier

2

Ho provato questo in FireFox 3.6.2 e sembra funzionare.

ho digitato questo direttamente nella riga di comando FireBug:

var proxied = eval; 
eval = function() { alert("ha"); return proxied.apply(this, arguments);}; 
eval(7); 
+2

Che non funziona in modo affidabile cross-browser e anche su Firefox, la tua versione con proxy mancherà della magia di cui parla Bobvin. –

+0

batch non definito [Break on this error] eval (7); FF 3.6.3pre – ko1ik

+0

So che non è * supposto * funzionare. Sto solo dicendo che sembra funzionare. –

4

Anche se non è portatile, il seguente approccio funziona in alcuni luoghi dove altrimenti non sarebbe (in quanto soddisfa i requisiti di ES5 che a) essere recuperate 'funzione built-standard' come un riferimento in un MemberExpression, non un valore e B) si traduce nel - ES5 #15.1.2)

(function() { 
    var proxied = window.eval 
    with({get eval(){ console.log('eval called'); return proxied }}) { 
    /* client code */ 
    } 
})() 

Questo ovviamente vale solo se si può avvolgere il codice del client in una con la dichiarazione(); anche se in molte situazioni, non dovrebbe essere difficile. Ovviamente, lo stesso approccio può ombreggiare window con un altro oggetto con tutte le sue proprietà e un proxy getter eval.

Ambienti che non supportano l'istruzione get di SpiderMonkey, potrebbero essere in grado di utilizzare defineProperty di ES5. Guardalo tu stesso.

+0

Errata: Manca un '}' in 'proxied}' – johnjohn

+2

@johnjohn su Stack Overflow, è possibile modificare le risposte di altre persone per suggerire modifiche. Solo per riferimento futuro. Ma grazie! Fisso. (= – ELLIOTTCABLE

+0

Fantastica idea, ma sembra una pratica orrenda – Oriol

0

forse non ho capito la domanda correttamente, ma io "override" eval() creando una funzione myEval() che ha l'originale eval() al suo interno ed eseguire operazioni di addizione in myEval().

function myEval = function(value){ 
    //do your stuff here 
    //for example 
    try { 
     value = eval(value) 
    } catch (error) { 
     console.log(error) 
     value = NaN 
    } 
    return value 
} 
+0

Dovresti fornire qualche spiegazione per il codice che hai postato. –

Problemi correlati