阅读数组的`length`属性真的很贵的JavaScript操作?
由于计算数组的长度非常昂贵,我总是假设在JavaScript中缓存数组的长度是一个好主意(特别是在for
循环中)。
例
for (var i = 0; i < arr.length; i++) { }
// vs
for (var i = 0, arrLength = arr.length; i < arrLength; i++) { }
然而,我想可能length
属性只是在创建和更改数组时进行更新。 因此,阅读它不应该太昂贵的操作,而不是阅读它存储在一个变量(而不是其他语言中的其他方法,可能需要在内存中寻找的东西,例如strlen()
在C中)。
我有两个问题。 我也对这是如何工作感兴趣,所以请不要用过早的优化棒撞我。
假设浏览器中的JavaScript引擎。
length
属性有什么好处吗? 读取对象属性的局部变量还有更多的参与吗? length
属性是否仅仅在创建时以及在不返回新数组并且另存为一个整数的shift()
和pop()
类型方法上进行了更改? 那么,我会说这是昂贵的,但后来我写了一个测试@ jsperf.com,令我惊讶的是我使用i<array.length
在Chrome中实际上更快,而在FF(4)中并不重要。
我怀疑是长度存储为一个整数(Uint32)。 根据ECMA规范(262版5,第121页):
每个Array对象都有一个长度属性,其值始终为小于232的非负整数。length属性的值在数值上大于名称为数组索引的每个属性的名称; 每当创建或更改Array对象的属性时,都会根据需要调整其他属性以保持此不变量。 具体来说,无论何时添加一个名称为数组索引的属性,如果需要,length属性将被更改为比该数组索引的数值多一个; 并且每当length属性发生更改时,将自动删除名称为数组索引且其值不小于新长度的每个属性。 此约束仅适用于Array对象的自身属性,并且不受可能从其原型继承的长度或数组索引属性的影响
唷! 我不知道我是否习惯了这种语言......
最后,我们总是有很好的滞后浏览器。 在IE(9,8,7)中,缓存的速度真的很快。 我说,不使用IE的很多理由之一。
TL; DR:
从我可以收集的数据看来,数组的长度在内部被缓存(至少在V8中)。
(详情?请阅读:))
所以,这个问题在我的脑海里萦绕了几次,我决定解决问题的根源(至少在一个实现中)。
挖掘V8源代码产生了JSArray类。
// The JSArray describes JavaScript Arrays
// Such an array can be in one of two modes:
// - fast, backing storage is a FixedArray and length <= elements.length();
// Please note: push and pop can be used to grow and shrink the array.
// - slow, backing storage is a HashTable with numbers as keys.
我假设数组元素的类型决定它是快还是慢。 我在set_has_fast_elements
( set_bit_field2(bit_field2() | (1 << kHasFastElements))
)中设置了一个标志位,这是我想要绘制挖掘线的地方,因为我正在寻找谷歌代码,而不是有本地来源。
现在看来, 任何时候在数组上完成任何操作(这是JSObject
一个子类,调用NormalizeElements()
,它将执行以下操作:
// Compute the effective length.
int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() :
array->length();
所以,在回答你的问题时:
length
属性似乎没有任何优势(除非你做了一些奇怪的事情,会迫使它slow
(我不确定那些是什么条件是) - 话虽如此,我很可能会继续缓存length
直到我有机会浏览所有OS浏览器实现;) length
属性似乎都会改变。 编辑:
在附注中,似乎“空”数组实际被分配为具有4个元素:
// Number of element slots to pre-allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
我不知道一旦超过界限,数组会增长多少个元素 - 我没有深入地挖掘过:)
另一组性能测试。 循环是通过一个有空循环的百万个随机数组完成的。
在Chrome中,具有缓存和非缓存长度的循环时钟几乎是同一时间,所以我猜测这是一个V8优化来缓存长度。
在Safari和Firefox中,缓存的长度始终比非缓存版本快两倍。
链接地址: http://www.djcxy.com/p/1881.html上一篇: Is reading the `length` property of an array really that expensive an operation in JavaScript?