作用域链对赋值的影响
- 块级作用域:在
if
块内声明的newVal
和temp
变量,它们具有块级作用域。在JavaScript中,块级作用域会形成新的作用域链。每次进入if
块,引擎会在该块级作用域查找变量,如果找不到再沿着作用域链向上查找。虽然块级作用域有助于代码的逻辑隔离,但频繁在块级作用域内声明和赋值变量,会增加作用域链查找变量的开销。
- 函数作用域:整个函数
complexFunction
有自己的函数作用域,变量result
、i
和外层的temp
都在这个作用域内。在函数作用域内,变量声明会被提升到函数顶部,但赋值不会。因此,在循环开始前声明result
和temp
,会使它们在整个函数作用域内可访问,而i
在ES6的let
关键字作用下,只在for
循环块内有效。
避免不必要的中间变量赋值
- 减少中间变量:代码中
temp
变量多次被赋值,部分赋值操作可以直接合并。例如:
- 原本
let temp = Math.pow(i, 2); result += temp;
可以直接写成 result += Math.pow(i, 2);
- 在
if
块内,let newVal = result * 2; temp = newVal / 3; result = temp + 10;
可以合并为 result = result * 2 / 3 + 10;
- 优化后代码:
function complexFunctionOptimized() {
let result = 0;
for (let i = 0; i < 10000; i++) {
result += Math.pow(i, 2);
if (result > 1000) {
result = result * 2 / 3 + 10;
}
}
return result;
}
性能提升预估
- 减少变量查找开销:优化后减少了块级作用域内变量声明和赋值,作用域链查找变量的次数减少,理论上会提升性能。具体提升程度难以精确预估,但在循环次数较多(如本题10000次)的情况下,这种优化效果会更明显。
- 减少赋值操作:优化后减少了中间变量
temp
和newVal
的赋值操作,减少了内存读写和计算开销,进一步提升性能。
测量性能差异的工具
- console.time() 和 console.timeEnd():
- 可以在函数调用前后分别使用
console.time()
和console.timeEnd()
来测量函数执行时间。例如:
console.time('original');
complexFunction();
console.timeEnd('original');
console.time('optimized');
complexFunctionOptimized();
console.timeEnd('optimized');
- Benchmark.js:这是一个专门用于JavaScript性能测试的库。它提供了更精确和全面的性能测试功能,支持多次运行测试、计算平均值、标准差等统计数据。例如:
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;
suite
.add('original', function() {
complexFunction();
})
.add('optimized', function() {
complexFunctionOptimized();
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is'+ this.filter('fastest').map('name'));
})
.run({ 'async': true });