然而,根据MDN的说明,除非特别使用BigInts,在JavaScript中所有数字都被表示为双精度浮点数。
如果我执行以下操作:
cont arr = [0, 1, 2, 3];
在V8引擎中的实际表示是什么?
V8的代码可以在github上找到这里,但我不知道该看哪里:
cont arr = [0, 1, 2, 3];
在V8引擎中的实际表示是什么?
V8的代码可以在github上找到这里,但我不知道该看哪里:
[0, 1, 2, 3]
会被存储为一个“Smi”数组。
什么是“Smi”?虽然JavaScript中的每个数字都必须像IEEE754双精度浮点数一样运作,但当V8可以时,它会将数字表示为“小整数”(31位有符号整数值+1位标记),即当数字在范围-2 ** 30
到2 ** 30-1
内具有整数值时,以提高效率。引擎通常可以在底层执行任何操作,只要事情的行为就像实现完全遵循规范一样。因此,当规范(或MDN文档)说“所有数字都是双精度浮点数”时,从引擎(或引擎开发人员)的角度来看,它实际上意味着“所有数字必须表现得好像它们是双精度浮点数”。
当一个数组只包含Smis时,数组本身会跟踪这一事实,以便从这样的数组加载的值知道它们的类型,而无需进行检查。这对于a [i] + 1
很重要,其中+
的实现在已知a
是Smi数组时不必检查a [i]
是否为Smi。
当存储在数组中的第一个超出Smi范围的数字时,它将转换为双精度浮点数数组(严格来说仍然不是“C ++数组”,而是垃圾回收堆上的自定义数组,但它类似于C ++数组,因此这是一种很好的解释方式)。
当存储在数组中的第一个非数字时,发生的情况取决于数组之前处于什么状态:如果它是“Smi数组”,那么只需要忘记它只包含Smis这一事实。无需重写,因为由于其标记位,Smis是有效的对象指针。如果数组以前是“double数组”,则确实需要对其进行重写,以便每个元素都是有效的对象指针。所有双精度浮点数将在此时作为所谓的“堆数字”(仅包装双精度值的托管堆上的对象)进行“装箱”。
总之,我想指出,在绝大多数情况下,没有必要担心这些内部实现技巧,甚至不需要意识到它们。尽管如此,我当然理解您的好奇心!此外,数组表示是微基准测试容易被误导的更常见原因之一,因为它们没有考虑实现细节,并可能会建议不适用于较大应用程序的结果。
回复评论:
不,它不支持 int16 存储方式。未来可能会改变,但如果有任何变化,我猜测未标记的 int32 更有可能被引入。如果实现发生任何变化,则可观察行为当然不会改变。V8有时甚至使用int16或更低。
稍微准确地说,将 Smis 数组转换为 doubles 数组有几个原因,例如:当将其转换为十进制时,它可能会成为 double
FixedArray
,它在 V8 中用于许多事情,包括作为 smi 或对象数组元素的后备存储。FixedDoubleArray
用于双精度数组的元素。正如我之前所说,它们不是 C++ 数组,但它们在内存中的布局类似。在整个 V8 代码库中都有处理各种类型数组的代码。 - jmrkbuiltins-array.cc
包含了一堆与数组相关的功能,但并没有数组对象的定义。 - jmrk