我發佈這個答案只是爲了讚美BoltClock's answer,通過直接觀看flash播放器源代碼提供了一些額外的見解。我們實際上可以看到專門提供此功能的AVM代碼,並且它是用C++編寫的。我們可以在裏面看到ArrayObject.cpp下面的代碼:
// Iterator support - for in, for each
Atom ArrayObject::nextName(int index)
{
AvmAssert(index > 0);
int denseLength = (int)getDenseLength();
if (index <= denseLength)
{
AvmCore *core = this->core();
return core->intToAtom(index-1);
}
else
{
return ScriptObject::nextName (index - denseLength);
}
}
正如你可以看到,當有一個合法財產(對象)返回,它是從ScriptObject
類擡頭,特別是nextName()
方法。如果我們看一下內ScriptObject.cpp這些方法:
Atom ScriptObject::nextName(int index)
{
AvmAssert(traits()->needsHashtable());
AvmAssert(index > 0);
InlineHashtable *ht = getTable();
if (uint32_t(index)-1 >= ht->getCapacity()/2)
return nullStringAtom;
const Atom* atoms = ht->getAtoms();
Atom m = ht->removeDontEnumMask(atoms[(index-1)<<1]);
if (AvmCore::isNullOrUndefined(m))
return nullStringAtom;
return m;
}
我們可以看到,確實如人在此間指出,虛擬機使用哈希表。然而,在這些函數中提供了一個特定的索引,乍一看,這就意味着必須有特定的順序。
如果你深入挖掘(我不會在這裏發佈所有的代碼),有不同類別的方法涉及for/for每個功能,其中一個方法是ScriptObject::nextNameIndex()
,它基本上拉起只要下一個值指向一個有效的對象,整個散列表就開始向表中的有效對象提供索引並增加參數中提供的原始索引。如果我對我的解釋是正確的,這將是你隨機查找的原因,我不相信在這裏有任何方法來強制這些操作中的標準化/有序地圖。
來源
對於那些誰可能想獲取Flash播放器的開源部分的源代碼,你可以從下面的善變庫抓住它(你可以像github上壓縮下載snapshop所以你不必安裝水銀):
http://hg.mozilla.org/tamarin-central - 這是「穩定」或「釋放」庫
http://hg.mozilla.org/tamarin-redux - 這是開發分支。 AVM的最新變化將在這裏找到。這包括對Android等的支持。 Adobe仍在更新和開放Flash播放器的這些部分,所以這是當前和官方的好東西。
雖然我在這裏,但這也可能是有趣的:http://code.google.com/p/redtamarin/。它是AVM的一個分支(而且相當成熟)的版本,可以用來編寫服務器端的動作腳本。整齊的東西,並有大量的信息,洞察AVM的運作,所以我想我也會收錄它。
我認爲上面聲明的對象的方式,就像一些其他語言中看到的散列表一樣,您可以永遠不會相信訂單,因爲它在內部處理自己的方式。一般的想法可以在這裏找到:http://en.wikipedia.org/wiki/Hash_table – ToddBFisher 2012-04-10 04:33:41
好問題。雖然我不知道爲什麼迭代對象屬性看起來是隨機的,我回憶過去的線程討論類似的問題,解決方案是創建一個字典,傳遞給按字典或鍵值排序的數組。我也有興趣知道這裏發生了什麼。 – TheDarkIn1978 2012-04-10 05:26:33
我認爲@ToddBFisher在這裏有正確的想法。在C++中,這基本上是一個「無序映射」,具體來說就是TR1版本中實現的新C++ 11標準中的std :: unordered_map。請參閱http://en.wikipedia.org/wiki/Unordered_associative_containers_(C%2B%2B)和http://www.cplusplus.com/reference/stl/map/瞭解更多關於工作概念的細節。 – 2012-04-10 06:24:03