为什么封装的Javascript函数有这么大的性能差异?

Joã*_*imo 21 javascript compiler-construction optimization performance v8

所以我有这个简单的代码:

function Run () {
  var n = 2*1e7;
  var inside = 0;
  while (n--) {
    if (Math.pow(Math.random(), 2) +
        Math.pow(Math.random(), 2) < 1)
      inside++;
  }

  return inside;
}

var start = Date.now();
Run();
console.log(Date.now() - start);
Run Code Online (Sandbox Code Playgroud)

它会输出大约335毫秒的时间.那很不错.但是,如果我像这样封装Run函数:

var d = Date.now();
(function Run () {
  var n = 2*1e7;
  var inside = 0;
  while (n--) {
    if (Math.pow(Math.random(), 2) +
        Math.pow(Math.random(), 2) < 1)
      inside++;
  }

  return inside;
})();
console.log(Date.now() - d);
Run Code Online (Sandbox Code Playgroud)

它将输出18319ms,这比以前的情况要糟糕得多.为什么是这样 ?

此外,如果重要,我在控制台的Chrome 26.0.1410.63上运行它.在node.js上,两个片段在控制台上都表现良好.

Esa*_*ija 3

函数减速和函数表达式对于优化没有任何区别,这将是荒谬的。


Google Chrome 中的控制台代码包含在with如下语句中:

 with ((console && console._commandLineAPI) || {}) {
      //Your code is concatenated here
 }
Run Code Online (Sandbox Code Playgroud)

因为函数声明被提升,所以前面的代码实际上是这样的:

function Run () {
  var n = 2*1e7;
  var inside = 0;
  while (n--) {
    if (Math.pow(Math.random(), 2) +
        Math.pow(Math.random(), 2) < 1)
      inside++;
  }

  return inside;
}

with ((console && console._commandLineAPI) || {}) {
  var start = Date.now();
  Run();
  console.log(Date.now() - start);
}
Run Code Online (Sandbox Code Playgroud)

所以声明是在声明之外 with运行的。事实上,在块中声明函数是无效的语法,函数声明只能是顶级语句

所以无论如何,由于历史原因,V8 很好,并且将其提升出来,而不是抛出语法错误:

var i = 3;

with({i:4}) {
    function test() {
        console.log(i);
    }
}
test();//logs 3 so it is obviously **not** under `with` influence
Run Code Online (Sandbox Code Playgroud)

所以因为声明不在withstatement下,所以运行速度会快很多。With 语句在 V8 下不可优化*,并且还会破坏词法作用域。


*不可优化意味着优化编译器不会查看代码,而只有通用编译器将为该函数生成代码。它类似于 Firefox 的解释器 vs JIT 模式。如果您想了解更多有关 V8 中哪些语言功能禁用优化的信息,请阅读优化杀手