当我在AS3中使用(i in object)时发生了什么?

时间:2012-04-10 04:21:32

标签: actionscript-3

要在AS3中迭代Object的属性,您可以使用for(var i:String in object),如下所示:

对象

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]

然而,选择属性的顺序似乎有所不同,并且永远不会匹配我能想到的任何内容,例如字母属性名称,创建它们的顺序等等。事实上,如果我尝试几次不同的时间在不同的地方,顺序完全不同。

是否可以按给定顺序访问属性?这里发生了什么?

2 个答案:

答案 0 :(得分:9)

通过直接查看Flash播放器源代码,我发布这个作为答案只是为了赞美BoltClock's answer并提供一些额外的见解。我们实际上可以看到专门提供此功能的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;
}

我们可以看到,确实,正如人们在此指出的那样,VM正在使用哈希表。然而,在这些功能中,提供了一个特定的索引,乍一看,这表明必须有特定的排序。

如果你深入挖掘(我不会在这里发布所有代码),每个功能中for / for中涉及的不同类都有一大堆方法,其中一个是方法ScriptObject::nextNameIndex()基本上拉起整个哈希表,只是开始为表中的有效对象提供索引,并递增参数中提供的原始索引,只要下一个值指向有效对象即可。如果我的解释是正确的,那么这就是你随机查找背后的原因,我不相信这里有任何方法可以在这些操作中强制使用标准化/有序地图。

<强>来源
对于那些可能想要获取flash播放器的开源部分的源代码的人,你可以从以下的mercurial存储库中获取它(你可以像github一样下载一个zipstore的snapshop,这样你就不必安装mercurial ):

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 :(得分: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,你会发现这样的实现。如上所述,在典型的哈希表中没有顺序或排序的概念。

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