现代引擎将在幕后使用真正的数组,即使您认为可以使用Array,如果您做了一些让他们认为他们不能使用真正的数组的事情,则退回到属性映射“数组”。
还要注意radsoc points out,var buffer = new ArrayBuffer(0x10000)然后var Uint32 = new Uint32Array(buffer)产生一个Uint32数组,其大小为0x4000(0x10000 / 4),而不是0x10000,因为你给ArrayBuffer的值是以字节为单位的,但当然每个 Uint32Array 条目有四个字节。以下所有内容都使用new Uint32Array(0x10000) 代替(并且一直这样做,甚至在这次编辑之前)来比较苹果和苹果。
所以让我们从 new Uint32Array(0x10000) 开始:http://jsperf.com/array-access-speed-2/11 (遗憾的是,JSPerf 丢失了这个测试及其结果,现在完全离线) p>
这表明,由于您以一种简单、可预测的方式填充数组,因此现代引擎会继续在幕后使用真正的数组(具有性能优势),而不是转移。我们看到两者的性能基本相同。速度上的差异可能与采用 Uint32 值并将其作为 number 分配给 sum 的类型转换有关(尽管如果不推迟类型转换,我会感到惊讶......)。
添加一些混乱,但是:
var Uint32 = new Uint32Array(0x10000);
var arr = [];
for (var i = 0x10000 - 1; i >= 0; --i) {
Uint32[Math.random() * 0x10000 | 0] = (Math.random() * 0x100000000) | 0;
arr[Math.random() * 0x10000 | 0] = (Math.random() * 0x100000000) | 0;
}
var sum = 0;
...因此引擎不得不依赖老式的属性映射“数组”,并且您会看到类型化数组的性能明显优于老式类型:http://jsperf.com/array-access-speed-2/3 (遗憾的是,JSPerf 已经失去了这个测试及其结果)
聪明的,这些 JavaScript 引擎工程师……
不过,您对 Array 数组的非数组性质所做的具体操作很重要;考虑:
var Uint32 = new Uint32Array(0x10000);
var arr = [];
arr.foo = "bar"; // <== Non-element property
for (var i = 0; i < 0x10000; ++i) {
Uint32[i] = (Math.random() * 0x100000000) | 0;
arr[i] = (Math.random() * 0x100000000) | 0;
}
var sum = 0;
这仍然可以预测地填充数组,但是我们向它添加了一个非元素属性 (foo)。 http://jsperf.com/array-access-speed-2/4 (遗憾的是,JSPerf 已经失去了这个测试及其结果) 显然,引擎非常聪明,并且在继续运行的同时将非元素属性放在一边为元素属性使用真正的数组:
我有点茫然地解释为什么标准数组应该比我们上面的第一个测试更快。测量误差? Math.random 中的变幻莫测?但我们仍然很确定 Array 中的特定于数组的数据仍然是一个真正的数组。
如果我们做同样的事情,但填写相反的顺序:
var Uint32 = new Uint32Array(0x10000);
var arr = [];
arr.foo = "bar"; // <== Non-element property
for (var i = 0x10000 - 1; i >= 0; --i) { // <== Reverse order
Uint32[i] = (Math.random() * 0x100000000) | 0;
arr[i] = (Math.random() * 0x100000000) | 0;
}
var sum = 0;
...我们回到类型化数组获胜——除了在 IE11 上:http://jsperf.com/array-access-speed-2/9 (遗憾的是,JSPerf 输掉了这个测试及其结果)