我创建了四个不同的函数,如下所示:
var normal = function() {
return;
};
var control = function() {
return;
alert("Hello, world!");
};
var withArguments = function() {
return;
arguments;
};
var withEval = function() {
return;
eval("");
};
由于它们都什么都不做并立即返回,所以我希望它们都具有相同的速度。但是之后在 jsPerf 上测试 http://jsperf.com/unexecuted-statements-after-return, 我发现normal
and control
执行大致相同,但是withArguments
and withEval
执行速度要慢得多。
为什么这些未执行的语句会对性能产生影响?既然没有被处决,又怎么可能有作用呢?
简而言之,调用eval
函数内部并能够访问arguments
array 都在函数调用期间使用额外的设置。如果已知两者都不是arguments
nor eval
将被执行,这个额外的设置可以被跳过。
编译器不会尝试预测是否arguments
数组实际上会被访问还是eval
实际上会被调用,它只检查它们是否存在于函数中。
arguments
在运行时调用使用以下参数的可变参数函数的成本更高arguments
对象而不是不使用的“正常”函数arguments
object.
绑定执行环境所需的额外步骤arguments
对象被声明为ECMA-262 标准第 10.6 节中指定 http://es5.github.io/#x10.6。创建arguments
object 是一个有点昂贵的 15 步过程。基本上,arguments
必须用传入的参数填充,并且.caller
and .callee
必须创建属性。
该标准规定,arguments
当函数进入其执行上下文时,应该创建对象,除非在名为的函数内部已经声明了参数、变量或函数arguments
.
出于优化的目的,大多数浏览器实际上不会创建参数对象,除非该函数在某处实际使用它(即使在return
)。这就是为什么您会在以下情况下看到性能下降的原因:arguments
被引用,即使包含它的行从未被执行。
eval
进入eval
代码,如ECMA-262 标准第 10.4.2 节中规定 http://es5.github.io/#x10.4.2,需要创建一个特殊的执行上下文。基本上,它必须将调用函数的执行上下文的所有属性绑定到eval
语境。
如果有多个eval
如果在一个函数中调用,它们基本上都会执行相同的过程两次。为了优化,如果浏览器检测到有eval
在函数中(即使在return
),它预先填充这个新的执行上下文,每个eval
可以使用,这样就不需要多次重新创建。
请注意,这些优化取决于浏览器,并且不是标准所要求的,因此某些浏览器实际上可能不会执行所描述的优化,或者它们可能会以不同的方式执行操作。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)