为什么typeof null的值在循环内部改变?
在Chrome控制台中执行此代码段:
function foo() { return typeof null === 'undefined'; } for(var i = 0; i < 1000; i++) console.log(foo());
应该打印1000次false
,但在某些机器上会打印false
的迭代次数,其余为true
。
为什么发生这种情况? 这只是一个错误?
有一个铬错误打开这个:
问题604033 – JIT编译器不保留方法的行为
所以是的这只是一个错误!
这实际上是一个V8 JavaScript引擎( Wiki )的错误。
此引擎用于Chromium,Maxthron,Android OS,Node.js等
在这个Reddit主题中可以find相对简单的错误描述 :
现代JavaScript引擎在执行时(即时编译)将JS代码编译为优化的机器代码,以使其运行速度更快。 然而,优化步骤有一些初始性能成本以换取长期加速,所以引擎根据使用的频率dynamic地决定一个方法是否值得。
在这种情况下,只有在优化的path中才出现错误,而未优化的path正常工作。 所以起初这个方法是按照预期工作的,但是如果它在某个时候被足够频繁地调用,那么引擎会决定优化它,并且用buggy版本replace它。
这个bug似乎已经在V8本身( 提交 )以及Chromium( bug报告 )和NodeJS( 提交 )中解决了。
为了回答它为什么会改变这个直接的问题,这个错误在Chrome使用的V8 JS引擎的“JIT”优化例程中。 起初,代码是按照书面的方式运行的,但是运行得越多,优化的好处就越有可能超过分析成本。
在这种情况下,在循环中重复执行之后,JIT编译器会分析该函数,并将其replace为优化版本。 不幸的是,分析做出了一个不正确的假设,而优化的版本实际上并没有产生正确的结果。
具体来说, Reddit用户RainHappens认为这是types传播中的一个错误:
它也做了一些types的传播(如在什么types的variables等可以)。 当variables未定义或为空时,有一个特殊的“不可检测”types。 在这种情况下,优化器“null无法检测,因此可以用”undefined“stringreplace以进行比较。
这是优化代码的难题之一:如何保证为了性能而重新编排的代码仍然具有与原始代码相同的效果。
这个在两个月前就已经修复了,很快就会在Chrome上面(已经在加那利)。
V8 Issue 1912553002 – 修正曲轴中的'typeof null'规范化
Chromium问题604033 – JIT编译器不保留方法行为