为什么 JavaScript 数组不是真正的数组
在讲 JavaScript 相关的东西前,让我先告诉你什么是 Array。
数组( Array )在内存中用一串连续的区域来存放一些值。注意「连续」一词,它至关重要。
上图表示存储在内存中的一个数组。存储4个4 bit 的元素,一共需要16 bit 存储区域,每个元素顺序保持一致。
假设,我声明了tinyInt arr[4],它占用从1201位置开始的一溜存储区域。当某个时刻我尝试读取a[2],那么只要做简单的计算,找到a[2]的位置就可以了。例如1201+(2X4)然后直接从1209位置读取数据。
在 JavaScript 中,数组是哈希映射。它可以通过多种数据结构实现,其中一种是链表。所以,如果在 JavaScript 中声明var arr = new Array(4);它会产生类似上图的结构。因此,如果你想在程序中某一处读取a[2],它必须从1201位置开始溯寻a[2]的位置。
这就是 JavaScript 数组和真正的数组不同的地方。显然数学计算要比链表遍历花的时间少。遇到长点的数组,日子就不好过了啊。
JavaScript 数组演进
如今, JavaScript 引擎已经在为同种数据类型的数组分配连续的存储空间了。优秀的开发者总是保持数组的数据类型一致,这样即时编译器 (JIT) 就能像 C 编译器一样通过计算读取数组了。
但是,如果你想在同种类型的数组中插入不同类型的元素,JIT 会销毁整个数组然后用以前的办法重建。
所以,如果你没写垃圾代码的话,JavaScript 的Array对象会维护一个真正的数组,这对现代 JS 开发者来说是一件大好事。
在 ES2015/ES6 中, 数组还有其它改进。 TC39 决定在 JavaScript 中引入类型化数组,所以如今我们有 ArrayBuffer了。
ArrayBuffer 会有一大块连续的存储位置,你能用它做任何你想做的事情。不过,直接处理内存涉及非常底层的操作,相当复杂。
所以我们有 Views** 来处理 ArrayBuffer。已经有一些可用的 View 了,未来还会加:
var buffer = new ArrayBuffer(8);
var view = new Int32Array(buffer);
view[0]=100;
如果你想知道更多有关类型化数组的信息,可以去看看MDN 文档
类型化数组性能良好且非常高效。WebGL 开发者因为缺少高效处理二进制数据的手段而经常面临性能问题,所以提出了类型化数组。
ArrayBuffer
ArrayBuffer 是 JavaScript 中的一个新类型,代表着一段连续的内存区域,分配完成后大小不能改变。它可以用来存储与复制二进制数据,例如图像、声音和视频等。
ArrayBuffer 对象的构造函数使用 new ArrayBuffer(length) 创建一个新的 ArrayBuffer 实例,length 是要分配的内存大小,以字节计算。
// 创建一个长度为 16 个字节的 ArrayBuffer 实例
const buffer = new ArrayBuffer(16);
ArrayBuffer 实例不能直接访问或修改其中的数据。为了访问和修改 ArrayBuffer 中数据的值,需要先创建一个视图对象,将其附加到 ArrayBuffer 上,然后通过视图对象来操作数据。 JavaScript 提供了多种视图对象,如 Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array 等,用于读/写特定类型的数据。这些视图对象构建在 ArrayBuffer 之上,可以访问和修改 ArrayBuffer 内部的数据内容。 例如,以下代码创建了一个 Int8Array 视图对象,并将其附加到之前创建的 ArrayBuffer 实例上。
// 创建一个长度为 16 个字节的 ArrayBuffer 实例
const buffer = new ArrayBuffer(16);
// 将 Int8Array 视图对象附加到 ArrayBuffer
const view = new Int8Array(buffer);
console.log(view.length); // 输出 16
// 通过视图对象修改 ArrayBuffer 中的数据
for (let i = 0; i < view.length; i++) {
view[i] = i;
}
console.log(view); // 输出 Int8Array(16) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
通过 Int8Array 视图对象,我们可以读取和修改 ArrayBuffer 中的数据内容。 ArrayBuffer 对象在现代 web 应用程序中被广泛使用,尤其是在处理大型图像和视频等二进制数据时。