运行动态Javascript代码
我正在做一个小游戏,其中一部分我想要一个非常简单的自定义编程语言。如果用户输入代码,比如运行动态Javascript代码,javascript,dynamic,interpreter,Javascript,Dynamic,Interpreter,我正在做一个小游戏,其中一部分我想要一个非常简单的自定义编程语言。如果用户输入代码,比如变量“helloWorld”=5,“解释器”会将变量更改为var,并删除引号,使其成为普通JavaScript 我应该如何运行该代码?我读过关于eval(),但也读过它速度慢,不应该使用。我已经研究过如何使用lexer、parser和tokenizer创建编程语言,但我不打算创建深入的东西 任何关于方向的帮助都会很好。您的语法可能会得到一些改进,但想法是这样的 首先,创建函数: function variab
变量“helloWorld”=5
,“解释器”会将变量更改为var,并删除引号,使其成为普通JavaScript
我应该如何运行该代码?我读过关于eval()
,但也读过它速度慢,不应该使用。我已经研究过如何使用lexer、parser和tokenizer创建编程语言,但我不打算创建深入的东西
任何关于方向的帮助都会很好。您的语法可能会得到一些改进,但想法是这样的 首先,创建函数:
function variable(name, value){
window[name] = value;
}
下一步是解析用户输入(这就是语法改进可以发挥作用的地方)。在您的示例中,您可以完全去掉引号,然后首先将字符串除以“=”,然后将其左半部分除以空格。得到3个元素,分别表示:
1) 函数名
2) 变量名
3) 可变值
然后,调用如下函数:
window[functionName](variableName, variableValie);
(function(){
// user script goes here. This will cause it to be in it's own scope!
})();
(function(){Array.isArray = function() { return 2;};})()
Array.isArray([]);
// returns 2
我假设您不需要“如何编写代码?”方面的帮助,而是需要如何执行用户脚本 关于
eval
:
eval
可以window[functionName](variableName, variableValie);
(function(){
// user script goes here. This will cause it to be in it's own scope!
})();
(function(){Array.isArray = function() { return 2;};})()
Array.isArray([]);
// returns 2
Javascript具有函数作用域,因此这将保护全局空间不被用户变量和函数填满。用户仍可能恶意影响全局变量,如下所示:
window[functionName](variableName, variableValie);
(function(){
// user script goes here. This will cause it to be in it's own scope!
})();
(function(){Array.isArray = function() { return 2;};})()
Array.isArray([]);
// returns 2
更多关于评估速度的信息。一个真实的例子:
正如你所见,“大评估”稍微慢一点。您可能会执行大评估,一次运行用户脚本的所有行。“邪恶评估”要慢得多,因为js引擎正在运行评估10000000次 这一切都取决于你真正想用你的语言做什么。我猜你真的不想让用户运行任意的javascript,它在你的应用所在的同一个全局空间中运行 因此,根据您真正想要做的事情,您不一定需要使用
eval()
。例如,让我们以您的陈述为例:
variable "helloWorld" = 5
假设您解析了它,并将其解析为一个数组中包含四项的语句对象:
var statement = ["variable", "helloWorld", "=", 5];
好的,您可以从数组中的第一项看到用户正在声明一个变量。现在,您可能不希望用户的变量进入全局命名空间(不使用eval()
的另一个原因)。因此,您可以为用户的变量创建一个对象:
var userVars = {};
现在,当您处理上述语句时,您将看到它是对用户变量的赋值,您只需将其转换为:
userVars[statement[1]] = statement[3];
现在,在名为userVars
的变量中有一个对象,其属性名为“helloWorld”
,值为5
。用户的变量都不在全局命名空间中,也不会影响您自己的程序操作
现在,很明显,如果您想进入详细的表达式和逻辑流,那么事情会变得比这更困难,但我希望您看到您可能不只是想在全局名称空间中使用eval()
执行任意用户javascript的另一种“安全”方法是将其放在iframe中,该iframe由与主网页不同的域托管。您可以将JS发送到服务器,并将其传递到另一台服务器(可能在同一个框中),然后为iframe提供服务,也可以使用
window.postMessage()
将JS文本传递到另一个协作iframe并在那里执行
由于iframe托管在不同的域上,因此它与您自己的网页和您自己的web应用服务器隔离。这就是JSFIDLE的基本工作方式,允许用户运行任意javascript,同时确保自己的应用程序免受多种攻击
或者,在使用
window.postmasage()
到一个独立的iframe的过程中,您甚至可以使用eval()
在另一个iframe中。如果用户的JS的目的是与您的游戏交互,那么您必须找出如何允许两个iframe相互通信,但要安全地进行。可以使用IE8或更新版本支持的window.postMessage()
来完成
隔离iframe的美妙之处在于它有自己的一组隔离的全局变量,除了通过
window.postMessage()公开的接口之外,它根本不能干扰你的游戏
如果您需要JavaScript的完整表达能力,那么请坚持使用更多人已经熟悉的原始JavaScript。使用原始JavaScript有两种可能性(没有限定的解析器):
eval()