2012-03-20 10 views
17

esiste un modo per eseguire eval() su un ambito specifico (ma NON globale)?Specificare l'ambito per eval() in JavaScript?

per esempio, il seguente codice non funziona (una non è definito sulla seconda istruzione), perché sono il diverso perimetro:

eval(var a = 1); 
eval(alert(a)); 

Se possibile, vorrei creare un ambito al volo . per esempio (la sintassi è sicuramente sbagliato, ma solo per illustrare l'idea)

var scope1; 
var scope2; 
with scope1{ 
    eval(var a = 1); eval(alert(a)); // this will alert 1 
} 
with scope2{ 
    eval(var a = 1); eval(a++); eval(alert(a)); // this will alert 2 
} 
with scope1{ 
    eval(a += 2); eval(alert(a)); // this will alert 3 because a is already defined in scope1 
} 

Qualche idea su come realizzare qualcosa di simile? Grazie!

+0

Nel caso qualcuno ancora interessato, io solo postato una risposta qui http://stackoverflow.com/a/43306962/1758245 –

risposta

13

è possibile utilizzare "use strict" per contenere il codice evalato all'interno di eval stesso.

In secondo luogo, eval di rigoroso codice di modalità non introduce nuove variabili nel campo di applicazione circostante. Nel codice normale eval("var x;") viene introdotta una variabile x nella funzione circostante o nell'ambito globale. Ciò significa che, in generale, in una funzione che contiene una chiamata a eval ogni nome che non fa riferimento a un argomento o variabile locale deve essere associato a una particolare definizione in fase di esecuzione (poiché tale eval potrebbe aver introdotto una nuova variabile che nascondeva la variabile esterna). In modalità rigorosa eval crea variabili solo per il codice in corso di valutazione, in modo da eval non può interessare se un nome si riferisce ad una variabile esterna o qualche variabile locale

var x = 17;          //a local variable 
var evalX = eval("'use strict'; var x = 42; x"); //eval an x internally 
assert(x === 17);         //x is still 17 here 
assert(evalX === 42);        //evalX takes 42 from eval'ed x 

Se una funzione è dichiarata con "l'uso strict ", tutto in esso verrà eseguito in modalità rigorosa. il seguente sarà fare lo stesso come sopra:

function foo(){ 
    "use strict"; 

    var x = 17; 
    var evalX = eval("var x = 42; x"); 
    assert(x === 17); 
    assert(evalX === 42); 
} 
+1

Come nota a margine, con 'use strict' il ** with ** causerà un'eccezione. Preventivo: con() le dichiarazioni {} sono morte quando la modalità strict è abilitata, infatti appare addirittura come un errore di sintassi. Fonte: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ –

+0

Non funziona per me. L'ho provato con Chrome – Zo72

+0

@Joseph il sognatore Non funziona per me. L'ho provato con Chrome. Quale browser dovrebbe supportare questo? – Zo72

1

Potete guardare nel progetto vm-browserify, che verrebbe utilizzato in combinazione con browserify.

Funziona creando s e eval codice in quello . Il codice è in realtà piuttosto semplice, quindi è possibile adattare l'idea di base per i propri scopi se non si desidera utilizzare la libreria stessa.

4

Creare le variabili che si desidera esistere nell'ambito come variabili locali in una funzione. Quindi, da quella funzione, restituisce una funzione definita localmente con un singolo argomento e chiama eval su di esso. L'istanza di eval utilizzerà l'ambito della sua funzione di contenimento, che è annidata nell'ambito della funzione di primo livello. Ogni invocazione della funzione di livello superiore crea un nuovo ambito con una nuova istanza della funzione eval. Per mantenere tutto dinamico, puoi anche usare una chiamata a eval nella funzione di primo livello per dichiarare le variabili che saranno locali a quell'ambito.

codice Esempio:

function makeEvalContext (declarations) 
{ 
    eval(declarations); 
    return function (str) { eval(str); } 
} 

eval1 = makeEvalContext ("var x;"); 
eval2 = makeEvalContext ("var x;"); 

eval1("x = 'first context';"); 
eval2("x = 'second context';"); 
eval1("window.alert(x);"); 
eval2("window.alert(x);"); 

https://jsfiddle.net/zgs73ret/

1

Ecco 20 linee o così classe JS che implementa un contesto estensibile utilizzando eval in un ambito lessicale:

// Scope class 
 
// aScope.eval(str) -- eval a string within the scope 
 
// aScope.newNames(name...) - adds vars to the scope 
 
function Scope() { 
 
    "use strict"; 
 
    this.names = []; 
 
    this.eval = function(s) { 
 
    return eval(s); 
 
    }; 
 
} 
 

 
Scope.prototype.newNames = function() { 
 
    "use strict"; 
 
    var names = [].slice.call(arguments); 
 
    var newNames = names.filter((x)=> !this.names.includes(x)); 
 

 
    if (newNames.length) { 
 
    var i, len; 
 
    var totalNames = newNames.concat(this.names); 
 
    var code = "(function() {\n"; 
 

 
    for (i = 0, len = newNames.length; i < len; i++) { 
 
     code += 'var ' + newNames[i] + ' = null;\n'; 
 
    } 
 
    code += 'return function(str) {return eval(str)};\n})()'; 
 
    this.eval = this.eval(code); 
 
    this.names = totalNames; 
 
    } 
 
} 
 

 

 
// LOGGING FOR EXAMPLE RUN 
 
function log(s, eval, expr) { 
 
\t s = '<span class="remark">' + String(s); 
 
    if (expr) { 
 
    s += ':\n<b>' + expr + '</b> --> '; 
 
    } 
 
    s += '</span>'; 
 
    if (expr) { 
 
    try { 
 
     s += '<span class="result">' + JSON.stringify(eval(expr)) + '</span>'; 
 
    } catch (err) { 
 
     s += '<span class="error">' + err.message + '</span>'; 
 
    } 
 
    } 
 
    document.body.innerHTML += s + '\n\n'; 
 
} 
 
document.body.innerHTML = ''; 
 

 

 
// EXAMPLE RUN 
 
var scope = new Scope(); 
 
log("Evaluating a var statement doesn't change the scope but newNames does (should return undefined)", scope.eval, 'var x = 4') 
 
log("X in the scope object should raise 'x not defined' error", scope.eval, 'x'); 
 
log("X in the global scope should raise 'x not defined' error", eval, 'x'); 
 
log("Adding X and Y to the scope object"); 
 
scope.newNames('x', 'y'); 
 
log("Assigning x and y", scope.eval, 'x = 3; y = 4'); 
 
log("X in the global scope should still raise 'x not defined' error", eval, 'x'); 
 
log("X + Y in the scope object should be 7", scope.eval, 'x + y'); 
 
log("X + Y in the global scope should raise 'x not defined' error", eval, 'x + y');
.remark { 
 
    font-style: italic; 
 
} 
 

 
.result, .error { 
 
    font-weight: bold; 
 
} 
 

 
.error { 
 
    color: red; 
 
}
<body style='white-space: pre'></body>

Problemi correlati