ale*_*lex 65 javascript arrays
我总是假设在JavaScript中缓存数组的长度是一个好主意(特别是在for
循环的条件下),因为计算数组的长度是昂贵的.
for (var i = 0; i < arr.length; i++) { }
// vs
for (var i = 0, arrLength = arr.length; i < arrLength; i++) { }
Run Code Online (Sandbox Code Playgroud)
但是,我想也许该length
属性只是在创建和更改数组时更新.因此,阅读它不应该是一个操作太昂贵而不是读取存储在变量中的操作(与其他语言中可能需要在内存中寻找某些内容的其他方法相反,例如strlen()
在C中).
我有两个问题.我也对它是如何工作感兴趣,所以请不要用过早的优化棒打我.
假设浏览器中的JavaScript引擎.
length
在JavaScript中缓存数组的属性有什么好处吗?是否有更多的参与在对象的属性上读取局部变量?length
属性是否仅在创建和on上更改,shift()
并且pop()
类型方法不返回新数组,否则只是存储为整数?Koo*_*Inc 47
嗯,我会说它很贵,但后来我写了一个小测试@ jsperf.com,令我惊讶的是,使用i<array.length
Chrome实际上更快,而在FF(4)中它并不重要.
我怀疑是长度存储为整数(Uint32).根据ECMA规范(262 ed.5,第121页):
每个Array对象都有一个length属性,其值始终是小于2 32的非负整数.length属性的值在数值上大于名称为数组索引的每个属性的名称; 无论何时创建或更改Array对象的属性,都会根据需要调整其他属性以保持此不变量.具体来说,每当添加名称为数组索引的属性时,如果需要,将更改length属性,使其大于该数组索引的数值; 每当更改length属性时,将自动删除名称为数值索引且值不小于新长度的每个属性.此约束仅适用于Array对象的自身属性,并且不受可能从其原型继承的长度或数组索引属性的影响
唷!我不知道我是否习惯了这种语言......
最后,我们总是让我们的老人落后于浏览器.在IE(9,8,7)中,缓存的长度确实更快.我说,不使用IE的更多原因之一.
Dem*_*cht 26
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.
Run Code Online (Sandbox Code Playgroud)
我假设数组元素的类型决定它是快还是慢.我得到了一些设置在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();
Run Code Online (Sandbox Code Playgroud)
所以,在回答你的问题时:
length
数组的属性似乎没有任何优势(除非你做了一些奇怪的事情会强制它slow
(我不确定那些条件是什么) ) - 说了这么多,我很可能继续缓存,length
直到我有机会完成所有 OS浏览器的实现;)length
进行任何操作后,该属性似乎都会被更改.编辑:
另外,似乎"空"数组实际上分配了4个元素:
// Number of element slots to pre-allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
Run Code Online (Sandbox Code Playgroud)
一旦超出界限,我不确定阵列增长了多少元素 - 我没深挖那么深的:)
本文通过询问IRHydra生成的代码来研究V8和Chrome中的自动缓存:
Grinch如何通过Vyacheslav Egorov 窃取array.length
他发现在某些条件下,手动缓存.length
实际上增加的开销而不是提高性能!
但是无论如何,这种微优化不可能为您的用户带来任何明显的收益。为了他们和您的利益,请专注于易于阅读的代码,并在代码中使用良好的数据结构和算法!
避免过早的优化:关注优美的代码,直到出现性能问题。只有这样,才能通过性能分析找出瓶颈,然后仅对代码的那部分进行优化。