一个值的内存表示,也就是它的大小,是一个实现细节,除非另有说明,并且可以根据运行时环境的底层代码而有所不同。运行时是运行 JavaScript 代码的应用程序,即 Nodejs、Firefox 浏览器或 Chrome 浏览器。
假设您编写自己的运行时并且想要表示一个布尔值。布尔值至少需要一位,因此您可以将其作为一位存储在内存中。
这是真的:
■
这是错误的:
□
但是没有什么能阻止你使用 8 位或 1 字节的内存空间。这里最高有效位保存值,其余将用 0 填充:
□□□□□□□■
或 64 位:
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■
同样的事情也适用于字符串值。您可以使用 8 位或 64 位甚至更多位来表示它。然而,语言承诺对任何 Unicode 值进行操作,但 8 位可能不足以表示所有 Unicode 值。这就是您在规范中找到一些地址和调整的地方。 JavaScript 中的字符串被视为 UTF-16 代码单元的序列,一些字符占用 16 位内存空间,而另一些则占用 32 位。
代码单元是从 Unicode 规范借用的术语。您可能会问为什么不是字符而是代码单元,因为字符是表示特定文本数据的一种方式,还有其他方式。例如,é、\u00E9 和 \u{E9} 都创建带有锐角的字母 e。在您的 JavaScript 字符串中,您可以选择其中任何一个。
数学很棘手,因为在 CPU 级别上,所有计算都是以二进制完成的,而二进制不会毫无问题地转换为十进制。尝试运行 0.1 + 0.1 == 0.3。因此,我们需要更严格地控制准确性。这就是为什么规范对数字表示非常具体:双精度 64 位二进制格式 IEEE 754。
总而言之,在编写 JavaScript 运行时,如何在内存中存储值取决于您,除非规范中明确规定。这就是为什么一些数据类型在内存中应该如何表示和存储的问题上进行了冗长的讨论。
运行时环境通常是用 C、C++ 或 Rust 等较低级别的语言编写的,并且内存管理被委托给这些语言使用的内容。
如果你是 JavaScript 程序员,你不需要关心内存是如何分配和释放的,因为运行时会为我们处理这部分。您唯一可能遇到的问题是循环引用导致的内存泄漏:对象 A 引用了对象 B,而对象 B 引用了对象 A。开发人员控制台中有一些工具可以检测此类问题。