2010-08-07 6 views
6

Perché non è possibile accedere alle variabili con ambito utilizzando eval in una dichiarazione with?Come mai eval non ha accesso alle variabili con scope sotto a con istruzione?

Ad esempio:

(function (obj) { 
    with (obj) { 
     console.log(a); // prints out obj.a 
     eval("console.log(a)"); // ReferenceError: a is not defined 
    } 
})({ a: "hello" }) 

EDIT: Come l'esperto CMS ha sottolineato, questo sembra essere un bug del browser (browser che utilizzano la console WebKit).

Se qualcuno si chiedeva che cosa abominevole che stavo cercando di venire con che richiederebbe sia il "male" e evalwith - Stavo cercando di vedere se potessi ottenere una funzione (utilizzata come un callback) eseguita in un altro contesto piuttosto che quello in cui è stato definito. E no, I probabilmente non lo uso da nessuna parte .. più curioso di ogni altra cosa.

(function (context,fn) { 
    with (context) 
     eval("("+fn+")()"); 
})({ a: "hello there" }, function() { console.log(a); }) 
+0

In quale browser stai ricevendo questo comportamento? Stai eseguendo il codice su qualche console? – CMS

+0

@CMS: Chrome 5.0.375.125 beta che utilizza la console di sviluppo integrata. Modifica: ho appena provato questo con Firefox (firebug) e ha funzionato come previsto. Deve essere un bug del browser come hai detto tu. –

+0

@Daniel - Funziona correttamente in Chrome 6.0.472.22 se questo aiuta qualsiasi –

risposta

5

Questo è un bug riproducibili solo dalla console del WebKit, che ha problemi di legame contesto chiamante quando eval viene richiamato da un FunctionExpression.

Quando viene effettuata una chiamata diretta del eval, il codice valutata come ci si aspetta dovrebbe condividere sia la variabile di ambiente:

(function (arg) { 
    return eval('arg'); 
})('foo'); 
// should return 'foo', throws a ReferenceError from the WebKit console 

E anche l'ambiente lessicale:

(function() { 
    eval('var localVar = "test"'); 
})(); 

typeof localVar; // should be 'undefined', returns 'string' on the Console 

Nella funzione di cui sopra localVar deve essere dichiarato nell'ambiente lessicale del chiamante, non nel contesto globale.

Per FunctionDeclaration s il comportamento è del tutto normale, se proviamo:

function test1(arg) { 
    return eval('arg'); 
} 
test1('foo'); // properly returns 'foo' on the WebKit console 

E

function test2() { 
    eval('var localVarTest = "test"'); 
} 
test2(); 
typeof localVarTest; // correctly returns 'undefined' 

sono stato in grado di riprodurre il problema sui seguenti browser in esecuzione su Windows Vista SP2:

  • Chrome 5.0.375.125
  • Chrome 6.0.472.25 dev
  • Safari 5.0.1
  • WebKit giornaliera costruzioni r64893
0

Eval funziona sempre in ambito globale, vero?

+0

No, una chiamata diretta a 'eval' utilizzerà il contesto di chiamata (sia l'ambiente lessicale e variabile del chiamante), una chiamata indiretta a eval in ECMAScript 5, ad es .:' var foo = eval; foo ('code'); 'userà il contesto globale, così come il costruttore Function. – CMS

1
(function (obj) { 
    with (obj) { 
     alert(a); // prints out obj.a 
     eval("alert(a)"); // ReferenceError: a is not defined 
    } 
})({ a: "hello from a with eval" }) 

function testfunc(a) { eval("alert(a)"); } testfunc("hello from a testfunc eval"); 

(function (a) { eval("alert(a)"); })("hello from a function constructor eval") 

funzionare bene: http://polyfx.com/jstest.html in FF/Chrome/Safari/IE.

Il problema con gli snippet di codice in esecuzione da varie console è che le console di solito si avvitano con il contesto. (Ad esempio, la console di Chrome non sembra essere propriamente avvolgente nel contesto globale, mentre la console di Firebug lo fa). Potrebbe essere un bug o (più probabile) potrebbe funzionare come previsto.

0

Mettendo eval e con parte, nuove bowsers includono il metodo ecma5 Function.prototype.bind per chiamare una funzione in ambito qualche dell'oggetto selezionato.

per browser meno recenti è possibile falso it-

Function.prototype.bind= Function.prototype.bind || function bind(scope){ 
    var method= this; 
    return function(){ 
     method.apply(scope, arguments); 
    } 
} 
+0

Si noti che la * funzione di fallback * non è conforme agli standard, non può precompilare o * curry * una funzione con argomenti noti. [Questa implementazione] (http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions/2025839#2025839) è la più vicina che puoi ottenere per conformarsi alla ES5 spec., in esecuzione su un motore ES3. Inoltre * il binding * di una funzione non darà accesso alla variabile o all'ambiente lessicale del chiamante (che sembra che l'OP voglia alla fine), può solo assicurare che il valore 'this' (e * gli argomenti curried *) siano mantenuti. – CMS

Problemi correlati