2012-04-10 97 views
10

要通過一個Object在AS3屬性迭代,你可以使用for(var i:String in object)這樣的:當我在AS3中使用(i對象)時發生了什麼?

對象:

var object:Object = { 

    thing: 1, 
    stuff: "hats", 
    another: new Sprite() 

}; 

循環:

for(var i:String in object) 
{ 
    trace(i + ": " + object[i]); 
} 

結果:

 
stuff: hats 
thing: 1 
another: [object Sprite] 

然而,選擇屬性的順序似乎有所不同,並且從未匹配任何我能想到的內容,例如按字母順序排列的屬性名稱,它們的創建順序等。實際上,如果我嘗試一些在不同的地方不同的時間,順序是完全不同的。

是否可以按給定順序訪問屬性?這裏發生了什麼?

+1

我認爲上面聲明的對象的方式,就像一些其他語言中看到的散列表一樣,您可以永遠不會相信訂單,因爲它在內部處理自己的方式。一般的想法可以在這裏找到:http://en.wikipedia.org/wiki/Hash_table – ToddBFisher 2012-04-10 04:33:41

+0

好問題。雖然我不知道爲什麼迭代對象屬性看起來是隨機的,我回憶過去的線程討論類似的問題,解決方案是創建一個字典,傳遞給按字典或鍵值排序的數組。我也有興趣知道這裏發生了什麼。 – TheDarkIn1978 2012-04-10 05:26:33

+1

我認爲@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

回答

9

我發佈這個答案只是爲了讚美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的運作,所以我想我也會收錄它。

+1

這是一個很好的答案,謝謝。 – Marty 2012-04-10 07:05:33

+1

沒問題。我將編輯它併發布人員可以獲取播放器的開源部分的源代碼。 – 2012-04-10 07:06:36

7

此行爲是documented(重點煤礦):

通過一個對象的屬性的for..in循環迭代,或陣列中的元素。例如,你可以使用一個for..in遍歷一個通用對象的屬性迭代(對象的屬性不保存在任何特定的順序,因此屬性可能以看似隨機的順序)

如何屬性存儲和檢索似乎是一個實現細節,這不包含在文檔中。正如ToddBFisher在評論中提到的那樣,通常用於實現關聯數組的數據結構是hash table。它甚至在this page about associative arrays in AS3中提及,如果你inspect the AVM code as shown by Ascension Systems,你會發現這樣的實現。如上所述,在典型的散列表中沒有命令或排序的概念。

我不相信有一種方法可以按特定順序訪問屬性,除非您以某種方式存儲該訂單。

相關問題