我有一个javascript文件,读取另一个文件,其中可能包含需要eval() - ed的javascript片段.脚本片段应该符合javascript的严格子集,这限制了它们可以做什么以及它们可以更改哪些变量,但我想知道是否有某种方法可以通过阻止eval在全局范围内查看变量来强制执行此操作.类似于以下内容:
function safeEval( fragment )
{
var localVariable = g_Variable;
{
// do magic scoping here so that the eval fragment can see localVariable
// but not g_Variable or anything else outside function scope
eval( fragment );
}
}
Run Code Online (Sandbox Code Playgroud)
实际的代码不需要看起来像这样 - 我对任何和所有带闭包的奇怪技巧都是开放的等等.但我确实想知道这是否可能.
Sho*_*og9 53
简答:不.如果它在全球范围内,它可用于任何事物.
答案很长:如果你是eval()不信任的代码,真的想要阅读或搞乱你的执行环境,那你就搞砸了.但是,如果您拥有并信任正在执行的所有代码,包括正在执行的代码eval(),您可以通过覆盖执行上下文来伪造它:
function maskedEval(scr)
{
// set up an object to serve as the context for the code
// being evaluated.
var mask = {};
// mask global properties
for (p in this)
mask[p] = undefined;
// execute script in private context
(new Function( "with(this) { " + scr + "}")).call(mask);
}
Run Code Online (Sandbox Code Playgroud)
我必须再次强调:
这仅用于屏蔽受信任的代码与执行它的上下文.如果您不信任代码,请不要
eval()(或将其传递给新代码Function(),或以任何其他方式使用它eval()).
Shog9? 的回答很棒。但是如果你的代码只是一个表达式,代码将被执行并且不会返回任何内容。对于表达式,使用
function evalInContext(context, js) {
return eval('with(context) { ' + js + ' }');
}
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它:
var obj = {key: true};
evalInContext(obj, 'key ? "YES" : "NO"');
Run Code Online (Sandbox Code Playgroud)
它将返回"YES"。
如果不确定要执行的代码是表达式还是语句,可以将它们组合起来:
function evalInContext(context, js) {
var value;
try {
// for expressions
value = eval('with(context) { ' + js + ' }');
} catch (e) {
if (e instanceof SyntaxError) {
try {
// for statements
value = (new Function('with(this) { ' + js + ' }')).call(context);
} catch (e) {}
}
}
return value;
}
Run Code Online (Sandbox Code Playgroud)
类似于with上面块方法中的动态函数包装脚本,这允许您向要执行的代码添加伪全局变量。您可以通过将特定事物添加到上下文中来“隐藏”它们。
function evalInContext(source, context) {
source = '(function(' + Object.keys(context).join(', ') + ') {' + source + '})';
var compiled = eval(source);
return compiled.apply(context, values());
// you likely don't need this - use underscore, jQuery, etc
function values() {
var result = [];
for (var property in context)
if (context.hasOwnProperty(property))
result.push(context[property]);
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
有关示例,请参见http://jsfiddle.net/PRh8t/。请注意,Object.keys并非所有浏览器都支持。
小智 6
我偶然发现我可以使用 Proxy 来限制范围对象,将变量屏蔽到范围之外似乎要容易得多。我不确定这种方法是否有缺点,但到目前为止它对我来说效果很好。
function maskedEval(src, ctx = {})
{
ctx = new Proxy(ctx, {
has: () => true
})
// execute script in private context
let func = (new Function("with(this) { " + src + "}"));
func.call(ctx);
}
Run Code Online (Sandbox Code Playgroud)
a = 1;
maskedEval("console.log(a)", { console });
maskedEval("console.log(a)", { console, a: 22});
maskedEval("a = 1", { a: 22 })
console.log(a)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
15829 次 |
| 最近记录: |