代码中语句的顺序和 js 引擎执行语句的顺序并不一定要一致。
var a, b;
a = 10; b = 30;
a = a + 1;
b = b + 1;
console.log( a + b ); // 42
这段代码中没有显式的异步(除了前面介绍过的很少见的异步 I/O !),所以很可能它的执 行过程是从上到下一行行进行的。
但是,js 引擎在编译这段代码之后可能会发现通过(安全地)重新安排这些语句的顺序有可能提高执行速度。重点是,只要这个重新排序是不可见的,一切都没问题。比如,引擎可能会发现,其实这样执行会更快:
var a, b;
a = 10; a++;
b = 30; b++;
console.log( a + b ); // 42
或者这样:
var a, b;
a = 11; b = 31;
console.log( a + b ); // 42
或者甚至这样:
// 因为a和b不会被再次使用
// 我们可以inline,从而完全不需要它们!
console.log( 42 ); // 42
前面的所有情况中,js 引擎在编译期间执行的都是安全的优化,最后可见的结果都是一样的。
但是这里有一种场景,其中特定的优化是不安全的,因此也是不允许的(当然,不用说这其实也根本不能称为优化):
var a, b;
a = 10; b = 30;
// 我们需要a和b处于递增之前的状态!
console.log( a * b ); // 300
a = a + 1;
b = b + 1;
console.log( a + b ); // 42
还有其他一些例子,其中编译器重新排序会产生可见的副作用(因此必须禁止),比如会产生副作用的函数调用(特别是 getter 函数),或 ES6 代理对象。
function foo() {
console.log( b );
return 1;
}
var a, b, c;
// ES5.1 getter字面量语法
c= {
get bar() {
console.log( a );
return 1;
} };
a = 10; b = 30;
a += foo();
b += c.bar;
// 30 // 11
console.log( a + b ); // 42
如果不是因为代码片段中的语句 console.log(..)
(只是作为一种方便的形式说明可见的副作用),js 引擎如果愿意的话,本来可以自由地把代码重新排序如下:
// ...
a = 10 + foo();
b = 30 + c.bar;
// ...