阅读数组的`length`属性真的很贵的JavaScript操作?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (19)

for由于计算数组的长度非常昂贵,我总是假设在JavaScript中缓存数组的长度是一个好主意(特别是在循环条件下)。

for (var i = 0; i < arr.length; i++) { }

// vs

for (var i = 0, arrLength = arr.length; i < arrLength; i++) { }

不过,我想也许该length属性只是在创建和更改数组时进行更新。因此,阅读它不应该太昂贵的操作,而不是阅读它存储在一个变量(而不是其他语言中的其他方法,可能需要在内存中寻找找到某物的结尾,例如strlen()在C中)。

我有两个问题。我也对这是如何工作感兴趣,所以请不要用过早的优化棒撞我。

假设浏览器中的JavaScript引擎。

  1. length在JavaScript中缓存数组属性有什么好处吗?读取对象属性的局部变量还有更多的参与吗?
  2. length属性是否仅仅在创建和on shift()pop()type方法上进行了更改,这些方法不会返回一个新数组,而只是将其存储为整数?
提问于
用户回答回答于

那么,我会说这是昂贵的,但后来我写了一个测试@ jsperf.com,令我惊讶的i<array.length是在Chrome中实际使用速度更快,在FF(4)中并不重要。

我怀疑是长度存储为一个整数(Uint32)。根据ECMA规范(262版5,第121页):

每个数组对象都有一个长度属性,其值始终是一个小于2 32的非负整数。length属性的值在数值上大于名称为数组索引的每个属性的名称; 每当创建或更改Array对象的属性时,都会根据需要调整其他属性以保持此不变量。具体来说,无论何时添加一个名称为数组索引的属性,如果需要,length属性将被更改为比该数组索引的数值多一个; 并且每当length属性发生更改时,将自动删除名称为数组索引且其值不小于新长度的每个属性。此约束仅适用于Array对象的自身属性,并且不受可能从其原型继承的长度或数组索引属性的影响

唷!我不知道我是否习惯了这种语言......

最后,我们总是有很好的滞后浏览器。在IE(9,8,7)中,缓存的速度真的很快。我说,不使用IE的很多理由之一。

用户回答回答于

从我可以收集的内容,数组的长度在内部被缓存(至少在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_elementsset_bit_field2(bit_field2() | (1 << kHasFastElements)))中设置了一个标志,这是我想要绘制挖掘线的地方,因为我正在查看谷歌代码并且本地没有源代码。

现在,它似乎任何时候任何操作是在阵列上完成(这是一个子类的JSObject,就会调用作出NormalizeElements(),其执行以下操作:

// Compute the effective length.
  int length = IsJSArray() ?
      Smi::cast(JSArray::cast(this)->length())->value() :
      array->length();

所以,在回答你的问题时:

  1. 在Chrome(或其他使用V8的浏览器)中缓存length数组的属性似乎没有任何优势(除非你正在做一些奇怪的事情来强制它)slow(我不确定这些条件是什么) - 话虽如此,我很可能继续缓存,length直到我有机会浏览所有 OS浏览器实现;)
  2. 对该对象length进行任何操作后,该属性似乎都会被更改。

在附注中,似乎“空”数组实际被分配为具有4个元素:

// Number of element slots to pre-allocate for an empty array.
static const int kPreallocatedArrayElements = 4;

我不知道一旦超过界限,数组会增长多少个元素 - 我没有深入地挖掘 :)

扫码关注云+社区