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

Why this huge performance difference for an encapsulated Javascript function?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);

它会输出335毫秒左右的时间,这很好。但是,如果我像这样封装run函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
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);

它将输出18319ms,比以前更糟。这是为什么?

另外,如果重要的话,我在控制台的Chrome26.0.1410.63上运行它。在node.js上,这两个代码段在控制台上运行良好。


函数分解和函数表达式与优化没有区别,这是荒谬的。

Google Chrome中的控制台代码包装在with语句中,如下所示:

1
2
3
 with ((console && console._commandLineAPI) || {}) {
      //Your code is concatenated here
 }

由于函数声明被挂起,前一个代码将有效地如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}

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

因此,不管怎样,由于历史原因,V8很好,可以将其提升,而不是抛出语法错误:

1
2
3
4
5
6
7
8
var i = 3;

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

因此,由于声明不在with语句下,所以运行得更快。在V8中,WITH语句不可优化*,还会破坏词法范围。

*不可优化意味着优化编译器不会查看代码,而只会为函数生成代码。它相当于火狐的解释器和JIT模式。如果你想更多地了解什么语言特性会禁用V8中的优化,请阅读优化杀手。