为什么typeof null的值在循环内发生变化?

Ago*_*gos 109 javascript v8

在Chrome控制台中执行此代码段:

function foo() {
    return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());
Run Code Online (Sandbox Code Playgroud)

应打印1000次false,但在某些机器上将打印false多次迭代,然后true用于其余部分.

在此输入图像描述

为什么会这样?这只是一个错误吗?

Slu*_*r86 74

有一个铬虫开放:

问题604033 - JIT编译器不保留方法行为

所以,这只是一个错误!

  • "只是"只是说这不是一个特征或一些奇怪的东西.是一个关键的错误,但只是一个错误! (6认同)
  • "只是"?难道这不能打破世界范围内任意的Web应用程序吗? (5认同)

Ser*_*kov 37

它实际上是一个V8 JavaScript引擎(Wiki)错误.

该引擎用于Chromium,Maxthron,Android OS,Node.js等.

您可以在此Reddit主题中找到相对简单的错误描述:

现代JavaScript引擎在执行时(Just In Time编译)将JS代码编译为优化的机器代码,以使其运行更快.然而,优化步骤具有一些初始性能成本以换取长期加速,因此引擎根据其使用的频率动态地决定方法是否值得.

在这种情况下,优化路径中似乎只有一个错误,而未优化的路径工作正常.因此,首先该方法按预期工作,但如果它在某个循环中经常被调用,则引擎将决定对其进行优化并将其替换为错误版本.

这个错误似乎已在V8本身(提交)以及Chromium(错误报告)和NodeJS(提交)中得到修复.


IMS*_*SoP 18

为了回答它为何发生变化的直接问题,该错误发生在Chrome使用的V8 JS引擎的"JIT"优化例程中.首先,代码完全按照书面运行,但运行得越多,优化的好处就越有可能超过分析成本.

在这种情况下,在循环中重复执行后,JIT编译器会分析该函数,并将其替换为优化版本.不幸的是,分析假设不正确,优化版本实际上并没有产生正确的结果.

具体来说,Reddit用户RainHappens表示它是类型传播中的错误:

它还进行某种类型的传播(如变量等可以是什么类型).当变量未定义或为null时,有一种特殊的"不可检测"类型.在这种情况下,优化器"无法检测到null,因此可以将其替换为"未定义"字符串以进行比较.

这是优化代码的难题之一:如何保证为性能重新排列的代码仍然具有与原始代码相同的效果.