JavaScript整数与小数运算速度差异:局部/全局变量为何表现不同?
局部变量vs全局变量:整数与小数运算的性能差异解析
测试代码
// 局部变量测试 (function() { var i, x; console.time('a'); for (i = x = 0; i < 1000000; x++) { if (x > 1000) { i++; x = 0; } } console.timeEnd('a'); console.time('b'); for (i = x = 0; i < 1000000; x += 0.001) { if (x > 1) { i++; x = 0; } } console.timeEnd('b'); })(); // 全局变量测试 var i, x; console.time('c'); for (i = x = 0; i < 1000000; x++) { if (x > 1000) { i++; x = 0; } } console.timeEnd('c'); console.time('d'); for (i = x = 0; i < 1000000; x += 0.001) { if (x > 1) { i++; x = 0; } } console.timeEnd('d');
测试结果
- 局部变量组:
a(整数运算)耗时约1200ms,b(小数运算)耗时约1200ms,两者性能几乎无差异 - 全局变量组:
c(整数运算)耗时约2300ms,d(小数运算)耗时约23000ms,d的速度比c慢了整整10倍
核心疑问
我理解局部变量因查找范围窄更快,但无法理解为何局部变量时整数与小数运算速度无差,全局变量时却差异巨大?
这是个非常有意思的性能观察!背后的核心原因在于JS引擎对局部变量和全局变量的优化策略完全不同:
1. 局部变量:封闭作用域带来的深度优化
以主流的V8引擎为例,局部变量的优势不止是查找范围窄:
- 局部变量存储在函数的栈帧中,引擎可以通过固定内存偏移量直接访问,不需要像全局变量那样去遍历对象属性链。
- 更关键的是,封闭的函数作用域让引擎能精准跟踪变量的类型变化。比如测试
b中,x虽然在整数(0)和浮点数之间切换,但引擎能预测到这种循环模式,直接生成优化后的机器码——甚至会把变量放到CPU寄存器中运算,把类型转换的开销降到可以忽略的程度。
2. 全局变量:开放性与类型波动击穿优化机制
全局变量挂载在全局对象(浏览器中是window)上,引擎对它的优化难度大很多:
- 全局对象是动态可变的,引擎无法保证
x不会被外部代码修改,因此很难维持稳定的缓存优化。 - 测试
d中的全局变量x频繁在小整数(Smi,V8对小整数的特殊优化存储)和堆浮点数(Heap Number)之间切换。每次类型切换都会导致引擎的内联缓存(IC)失效——原本为快速访问属性建立的缓存不再适用,引擎不得不退回到慢路径,每次读写x都要重新检查类型、查找属性,这直接把浮点数运算的开销放大了数倍。 - 而测试
c中的全局变量x始终是整数类型,引擎能维持稳定的内联缓存,所以虽然比局部变量慢,但性能下降幅度远不如d。
简单总结:局部变量的封闭性让引擎可以大胆做深度优化,哪怕类型有规律切换也能高效处理;而全局变量的开放性加上类型频繁波动,直接击穿了引擎的优化机制,导致小数运算的开销被急剧放大。
内容的提问来源于stack exchange,提问作者msm082919
相关产品推荐
相关产品推荐

