2012-03-20 12 views
17

¿hay alguna forma de ejecutar eval() en un ámbito específico (pero no global)?Especifique el alcance para eval() en JavaScript?

por ejemplo, el siguiente código no funciona (una está definida en la segunda declaración) porque están en distinto alcance:

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

Si es posible, me gustaría crear una cobertura sobre la marcha . por ejemplo (la sintaxis es definitivamente mal, pero sólo para ilustrar la 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 
} 

Alguna idea sobre cómo lograr algo como esto? ¡Gracias!

+0

En caso de que alguien siga interesado, solo publicó una respuesta aquí http://stackoverflow.com/a/43306962/1758245 –

Respuesta

13

puede usar el "use strict" para contener el código evaluado dentro de la evaluación en sí.

En segundo lugar, eval de código de modo estricto no introduce nuevas variables en el ámbito que rodea. En el código normal eval("var x;") introduce una variable x en la función circundante o en el alcance global. Esto significa que, en general, en una función que contiene una llamada a eval, todos los nombres que no se refieran a un argumento o variable local deben correlacionarse con una definición particular en tiempo de ejecución (porque eval podría haber introducido una nueva variable que ocultaría la variable externa) En modo estricto eval crea las variables sólo para el código que está siendo evaluado, por lo eval no pueden determinar si un nombre se refiere a una variable externa o alguna variable local

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 

Si una función se declara con "uso estricto ", todo en él se ejecutará en modo estricto. la siguiente hará lo mismo que el anterior:

function foo(){ 
    "use strict"; 

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

Como nota al margen, con 'use strict' el ** con ** causará una excepción. Cita: con() {} las declaraciones están muertas cuando el modo estricto está habilitado; de hecho, incluso aparece como un error de sintaxis. Fuente: http://ejohn.org/blog/ecmascript-5-strict-mode-json-andmore/ –

+0

No funciona para mí. Lo intenté con Chrome – Zo72

+0

@Joseph the dreamer No funciona para mí. Lo intenté con Chrome. ¿Qué navegador se supone que es compatible con esto? – Zo72

1

Usted puede mirar en el proyecto vm-browserify, que se utiliza en conjunción con browserify.

Funciona mediante la creación de s, y eval ing el código en ese . El código es realmente bastante simple, por lo que podría adaptar la idea básica para sus propios fines si no desea usar la biblioteca en sí.

4

Cree las variables que desea que existan en su ámbito como variables locales en una función. Luego, desde esa función, devuelve una función definida localmente que tiene un único argumento y llama al eval. Esa instancia de eval usará el alcance de su función contenedora, que está anidada dentro del alcance de su función de nivel superior. Cada invocación de la función de nivel superior crea un nuevo ámbito con una nueva instancia de la función eval. Para mantener todo dinámico, puede usar una llamada al eval en la función de nivel superior para declarar las variables que serán locales para ese alcance.

código Ejemplo:

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

Aquí está una línea 20 o así clase JS que implementa un contexto extensible usando eval en un ámbito léxico:

// 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>