访问一个数组元素或对象属性将花费大约相同的时间,无论大小如何。
添加数据会有所不同,具体取决于我们谈论的是数组还是非数组对象,以及添加数据的位置和方式。
我不能谈论任何特定 JavaScript 引擎的细节,但通常可变长度数组实现有两种不同的长度:已分配长度和当前长度。您在 JavaScript 中看到的 array.length 属性是 current 长度,但分配给数组的内存通常大于此长度。例如,一个包含 100 个元素的数组实际上可能会为 128 个元素分配足够的空间。
所以当你调用array.push() 时,数组数据中可能已经有多余的空间了。这个案子非常快。代码只需要增加.length并存储新的数组元素。
这就是为比当前长度更多的元素分配空间的原因:以避免必须在每个 .push() 上重新分配内存。
但是,一旦当前长度达到分配的长度,下一个.push() 需要重新分配整个数组,并且通常必须将所有先前的数组元素复制到新的内存位置。这使得这个特定的.push() 慢得多。但是,随后的.push() 调用会很快,直到当前长度再次达到分配的长度。
在某些情况下,重新分配可能发生在适当的位置 - 可能恰好在数组末尾之后有未分配的空间,因此它可以在不复制的情况下扩展 - 但这种情况不太常见。
这种重新分配的确切策略各不相同:引擎可能会在需要重新分配时立即将分配的数组长度加倍,或者将长度乘以 1.5,或者它选择的任何值。
现在,如果您使用array.unshift() 或array.splice() 在数组的开头 处或附近插入一个或多个元素会怎样?在这种情况下,即使分配的数组长度有空间容纳额外元素,速度也将取决于当前数组长度,因为插入点之后的所有现有元素都必须在内存中移动。
这对于非数组对象来说不是一个因素。添加新属性,无论其键值如何,都不需要移动所有现有属性。对于具有大量属性的对象,它可能会稍微慢一些,但与在数组开头附近添加元素的方式不同。对象是用哈希表或类似的数据结构实现的。当哈希冲突过多(映射到相同哈希值的键)时,引擎可能会决定重新分配哈希表以使其更大,但这将与您添加的任何键值大致相同。键是“小于”还是“大于”任何现有值在这里都无关紧要。
如果您有更具体的问题,我们可以进一步讨论。