10

我经常在函数中有可选参数,但一些测试显示它们在 Firefox 和 safari (70-95%) 中对它们的性能造成了巨大影响。奇怪的是,如果我传入未定义的字面值,那么就没有惩罚。这里会发生什么?我不会认为这是一个作用域链问题,因为它们本质上是函数本地的。我要开始将undefined传递给每个可选参数吗?

jsPerf:http: //jsperf.com/function-undefined-args/2

4

2 回答 2

5

对于这样的功能:

function threeArgs(x, y, z) {
  return x + y + z;
}

就是这样称呼的:

threeArgs(1, 2, 3);

优化器可以自由选择不生成任何代码。它很容易确定没有副作用,因为该函数只是引用其参数值并返回简单表达式的结果。由于返回值被忽略,运行时根本没有理由做任何事情。

除此之外,如果代码是:

something += threeArgs(1, 2, 3);

优化器可能决定生成大致相当于:

something += 6;

为什么?因为调用是用数字常量进行的,它可以在代码生成时安全地折叠它们。这可能是保守的,因为数字很奇怪,但这里它们都是整数,所以它可以很好地做到这一点。即使没有,它也可以安全地内联函数:

something += 1 + 2 + 3;

但是,当缺少参数时,优化器可能会退出并生成真正的函数调用。对于这样一个简单的函数,函数调用的开销很容易导致性能上的巨大差异。

通过在测试中使用变量而不是常量,并且通过实际使用函数的返回值,您可以“混淆”优化器并防止它跳过调用或预先计算结果,但您不能阻止它内联。由于这个原因,我仍然认为您的结果很有趣:它暴露了这样一个事实,即(无论如何)这些优化器对调用函数的方式很敏感。

于 2012-09-30T16:12:42.263 回答
2

我认为可以解释性能差异的原因是参数传递给函数对象的方式:通过arguments对象。当不传递任何参数时,JS 将首先扫描任何给定参数的 arguments 对象,当这些参数未定义时,arguments原型链将被扫描,一直到Object.prototype. 如果这些都缺少所需的属性,JS 将返回undefined. 然而,显式传递 undefined ,将其设置为直接在 arguments 对象上的属性:

function foo(arg)
{
    console.log(arguments.hasOwnProperty('0'));
}
foo();//false'
foo('bar');//true
foo(undefined);//true

我认为这就是为什么明确传递未定义往往更快的原因。

于 2012-09-30T16:10:57.303 回答