在 JavaScript 中指定 eval() 的范围?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9781285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Specify scope for eval() in JavaScript?
提问by hiukim
is there any way I can execute eval() on a specific scope (but NOT global)?
有什么方法可以在特定范围(但不是全局)上执行 eval( )吗?
for example, the following code doesn't work (a is undefined on the second statement) because they are on different scope:
例如,以下代码不起作用(a 在第二个语句中未定义),因为它们在不同的范围内:
eval(var a = 1);
eval(alert(a));
If possible, I would like to create a scope on the fly. for example (the syntax is definitely wrong, but just to illustrate the 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
}
Any idea on how to achieve something like this? Thanks!
关于如何实现这样的目标的任何想法?谢谢!
回答by Joseph
you can use the "use strict"to contain the eval'ed code within the eval itself.
您可以使用“使用严格”在 eval 本身中包含 eval'ed 代码。
Second,
eval
of strict mode code does not introduce new variables into the surrounding scope. In normal codeeval("var x;")
introduces a variablex
into the surrounding function or the global scope. This means that, in general, in a function containing a call toeval
every name not referring to an argument or local variable must be mapped to a particular definition at runtime (because thateval
might have introduced a new variable that would hide the outer variable). In strict modeeval
creates variables only for the code being evaluated, so eval can't affect whether a name refers to an outer variable or some local variable
其次,
eval
严格模式的代码不会在周围的作用域中引入新的变量。在普通代码中,eval("var x;")
将变量x
引入周围的函数或全局范围。这意味着,一般来说,在包含对eval
每个不引用参数或局部变量的名称的调用的函数中,必须在运行时映射到特定定义(因为这eval
可能引入了一个新变量来隐藏外部变量)。在严格模式下eval
只为被评估的代码创建变量,所以 eval 不能影响名称是指外部变量还是某个局部变量
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
If a function is declared with "use strict", everything in it will be executed in strict mode. the following will do the same as above:
如果函数声明为“use strict”,则其中的所有内容都将以严格模式执行。以下将执行与上述相同的操作:
function foo(){
"use strict";
var x = 17;
var evalX = eval("var x = 42; x");
assert(x === 17);
assert(evalX === 42);
}
回答by Periata Breatta
Create the variables you want to exist in your scope as local variables in a function. Then, from that function, return a locally-defined function that has a single argument and calls eval
on it. That instance of eval
will use the scope of its containing function, which is nested inside the scope of your top level function. Each invocation of the top level function creates a new scope with a new instance of the eval function. To keep everything dynamic, you can even use a call to eval
in the top level function to declare the variables that will be local to that scope.
创建您希望存在于作用域中的变量作为函数中的局部变量。然后,从该函数返回一个本地定义的函数,该函数具有单个参数并对其进行调用eval
。该实例eval
将使用其包含函数的作用域,该函数嵌套在您的顶级函数的作用域内。每次调用顶级函数都会创建一个具有 eval 函数新实例的新作用域。为了保持一切动态,您甚至可以eval
在顶级函数中使用调用来声明该范围内的局部变量。
Example code:
示例代码:
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);");
回答by Hypersoft Systems
Simple as pie.
简单如馅饼。
// Courtesy of Hypersoft-Systems: U.-S.-A.
function scopeEval(scope, script) {
return Function('"use strict";return (' + script + ')').bind(scope)();
}
scopeEval(document, 'alert(this)');
回答by Bill Burdick
Here is a 20-line or so JS class that implements an extensible context using eval in a lexical scope:
这是一个 20 行左右的 JS 类,它在词法范围内使用 eval 实现了一个可扩展的上下文:
// 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) {
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>
回答by Domenic
You can look into the vm-browserifyproject, which would be used in conjunction with browserify.
您可以查看vm-browserify项目,该项目将与browserify结合使用。
It works by creating <iframe>
s, and eval
ing the code in that <iframe>
. The code is actually pretty simple, so you could adapt the basic idea for your own purposes if you don't want to use the library itself.
它的工作原理是创建<iframe>
s,然后eval
在<iframe>
. 代码实际上非常简单,因此如果您不想使用库本身,则可以根据自己的目的调整基本思想。
回答by chickens
This worked for me the best:
这对我最有效:
const scopedEval = (scope, script) => Function(`"use strict"; ${script}`).bind(scope)();
Usage:
用法:
scopedEval({a:1,b:2},"return this.a+this.b")
回答by rayscan
The approach here was to allow a context object to parameterize the evaluation of the expression.
这里的方法是允许上下文对象参数化表达式的评估。
First a function is created using the Function() constructorthat accepts every key of the context as well as the expression to evaluate; the body returns the evaluated expression. Then that function is called with all of the values of the context and the expression to evaluate.
首先使用Function() 构造函数创建一个函数,该构造函数接受上下文的每个键以及要计算的表达式;主体返回计算后的表达式。然后使用上下文的所有值和要计算的表达式调用该函数。
function scopedEval(context, expr) {
const evaluator = Function.apply(null, [...Object.keys(context), 'expr', "return eval(expr)"]);
return evaluator.apply(null, [...Object.values(context), expr]);
}
// Usage
const context = {a: 1, b: 2, c: {d: 3}};
scopedEval(context, "a+b+c.d"); // 6
By using Function.prototype.applythe number of arguments and the names don't need to be known beforehand. Because the arguments are scoped to the evaluator
function they are directly accessible from the expression (instead of requiring this.a
).
通过使用Function.prototype.apply不需要事先知道参数的数量和名称。因为参数的范围是evaluator
函数,所以它们可以从表达式直接访问(而不是 require this.a
)。
回答by gazdagergo
The poor man's method:
穷人的方法:
If your scope is not too dynamic, just a couple of static and read-only declarations, simply put it in a string and concatenate with the string what you wanna execute like this:
如果您的范围不是太动态,只需几个静态和只读声明,只需将它放在一个字符串中并与您想要执行的字符串连接,如下所示:
const scopeAll = `
const myFunc = (a, b) => a + b + s;
`
const scope1 = `
${scopeAll}
const s = 'c';
`
const scope2 = `
${scopeAll}
const s = 'd';
`
const myStringToExecute = `
myFunc('a', 'b')
`
console.log(eval(scope1 + myStringToExecute));
console.log(eval(scope2 + myStringToExecute));