我将其发布为答案只是为了通过直接查看 Flash 播放器源代码来补充BoltClock 的答案,并提供一些额外的见解。我们实际上可以看到专门提供此功能的 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 in/for 每个功能中涉及到来自不同类的大量方法,其中一个是ScriptObject::nextNameIndex()
基本上提取整个哈希表的方法和只要下一个值指向有效对象,就开始为表中的有效对象提供索引并递增参数中提供的原始索引。如果我的解释是正确的,这将是您随机查找背后的原因,我不相信这里有任何方法可以在这些操作中强制使用标准化/有序映射。
来源
对于那些可能想要获取 Flash 播放器的开源部分的源代码的人,您可以从以下 mercurial 存储库中获取它(您可以像 github 一样下载 zip 中的 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 的工作原理,所以我想我也会包括它。