我正在用JavaScript编写一个简单的REPL(读取,评估,打印,循环)实现。我能够隔离代码并调用上下文,如下所示:
var sandbox = {
// Allow the input code to use predefined helper functions
// without the preceding use of the this keyword.
helper_fn: function() { alert("foo"); }
};
var func = new Function("with (this) { " + user_inputed_code + " }");
func.call(sandbox);
现在关闭user_inputed_code
,以便this
引用sandbox
,如果输入的代码访问或变异this
,则会影响sandbox
。
但是,我注意到如果插入的代码意外忘记用关键字var
作为变量赋值的序言,那么全局命名空间就会被污染。
反正有没有阻止这个?如果是这样(也许是正则表达式?)?有没有更好的方法来解决这个问题?
答案 0 :(得分:2)
我将提供两种完全不同于其他人在此讨论的方法。它们都很激烈,当你想要相对隔离你的环境时它们很有用。
更具体地说,如果您正在构建REPL,请查看我们讨论的this answer,并使用iframe的第一种方法解释如何在相同范围内但在全局范围之外评估代码。 / p>
(我假设一个浏览器,在节点中你可以简单地使用vm模块并在runInContext中选择上下文)
答案 1 :(得分:1)
事实证明"use strict"
和Object.freeze
有一种方式。您必须使用自己的沙箱对象手动替换全局命名空间:
var sandbox, module, func, output;
// Empty object or with defined methods / properties
// you want to expose as globals.
sandbox = {};
// A reference to an object you WANT to provide safe
// access to. In this example it's just an empty object.
module = {};
// A better version of eval:
func = new Function("module", "with(this){return(function(module,global,window){\"use strict\";return eval(\"" + code + "\");})(module,this,this)}");
output = func.call(sandbox, module);
此代码允许全局和窗口引用沙盒对象而不是全局名称空间。它伪装变量global
和window
作为沙箱对象,如果输入错过了"use strict"
的使用,var
的使用将导致它抛出异常。它还将函数包装在with
语句中,以使沙盒对象中定义的方法和属性像this.
前面一样工作。要查看实施示例(包含测试规范),请查看this gist。
谢谢大家的意见。希望这个答案有助于其他人。