2012-04-10 101 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,你会发现这样的实现。如上所述,在典型的散列表中没有命令或排序的概念。

我不相信有一种方法可以按特定顺序访问属性,除非您以某种方式存储该订单。

相关问题