所以我正在尝试创建我自己的JS框架,仅仅是为了我自己的乐趣(并且可能转换为有用的)并且我大部分时间都专注于动态生成JS(因为JS具有更高级别的语言 - 在 - 中间是坏主意,IMO)
我遇到了一个麻烦。我试图做以下
var f = null;
var converted = "f = function(){ <do something here>";
for(var x in list)
converted+=list[x];
converted+="};";
eval(converted);
所以这几乎将构造函数写入f,以后我可以执行。
但是这里有捕获 - 它运行得比我刚刚在文件中完全编写f代码要慢,这很奇怪。让我解释为什么它对我来说很奇怪:当你每次运行eval时,Chrome预编译器(或任何浏览器预编译器 - chrome是我的目标)都无法缓存 - 编译代码,因为它预计会随着每个代码而改变跑。
但是,当您将其保存到某个函数时,它会创建一个新的VM计算机文件,因为在保存该函数的代码后,您无法更改它。那么,为什么,当我这样做时,它比正常执行运行得慢?我的意思是代码执行不止一次。为什么这很重要?
PS:我上面显示的方法,每次进行评估的速度更快。所以我不明白为什么秒表在中间显示时间,再次忽略前1-10次呼叫
PPS:测试用例:http://jsperf.com/evaluated-function-vs-real-function/2
答案 0 :(得分:4)
eval
基本上是不可优化的,因为编译器不知道它在做什么。即使将其保存到函数中,编译器也必须选择退出很多优化,因为以某种方式更改代码可能会破坏eval函数。
这就是为什么通常,当你需要做一个eval时,你可以在另一个函数中执行:这样,编译器可以确保你没有修改eval
中的局部范围,并优化了好多了。
JS VMs真的很多关于启发式方法。他们试图猜测你想做什么,并针对一般情况进行优化。 eval
(或new Function
)阻止他们做很多事情。
Function.new
可能会更快一点,因为编译器会知道它不会尝试修改范围。
还!请注意,eval
可能与您习惯的有所不同。例如,eval('a')
和(0, eval)('a')
不一样:
我将用这个
来演示它window.a = 5;
void function () {
var a = 1;
eval('a = 2');
console.log(a);
console.log(window.a);
}();
这将打印1
然后5
window.a = 5;
void function () {
var a = 1;
(0,eval)('a = 2'); // <- this line has changed
console.log(a);
console.log(window.a);
}();
然而,这将打印1
然后2
。