Что происходит, когда я использую (i в объекте) в AS3?

Чтобы перебрать свойства Object в AS3, вы можете использовать for(var i:String in object) следующим образом:

Объект:

var object:Object = {

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

};

Loop:

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

Результат:

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

Порядок выбора свойств, однако, кажется, меняется и никогда не совпадает с тем, что я могу представить, например, именем алфавитного свойства, порядком, в котором они были созданы, и т.д. На самом деле, если я попробую несколько раз в разных местах порядок совершенно другой.

Можно ли получить доступ к свойствам в заданном порядке? Что здесь происходит?

Ответ 1

Я размещаю это как ответ, просто чтобы отблагодарить ответ BoltClock с некоторым дополнительным пониманием, посмотрев прямо на исходный код flash-плеера. Мы действительно можем увидеть AVM-код, который специально предоставляет эту функциональность и написан на С++. Мы можем видеть внутри 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;
}

Мы видим, что действительно, поскольку люди указали здесь, что виртуальная машина использует хеш-таблицу. Однако в этих функциях имеется определенный индекс, который, на первый взгляд, предполагал, что тогда должно быть определенное упорядочение.

Если вы копаете глубже (я не буду публиковать весь код здесь), существует целый набор методов из разных классов, участвующих в in/для каждой функциональности, и один из них - это метод ScriptObject::nextNameIndex(), который в основном тянет вверх по всей хеш-таблице и просто начинает предоставлять индексы действительным объектам в таблице и увеличивает исходный индекс, предоставленный в аргументе, если следующее значение указывает на действительный объект. Если я прав в своей интерпретации, это будет причиной вашего случайного поиска, и я не верю, что здесь можно было бы заставить стандартизованную/упорядоченную карту в этих операциях.

Источники
Для тех из вас, кто может захотеть получить исходный код для части с открытым исходным кодом флеш-плеера, вы можете захватить его из следующих ртутных репозиториев (вы можете загрузить snapshop в zip, как github, так что вам не нужно устанавливать меркурийные ):

http://hg.mozilla.org/tamarin-central - это "стабильный" или "освобождающий" репозиторий

http://hg.mozilla.org/tamarin-redux - Это ветка развития. Самые последние изменения в AVM будут найдены здесь. Это включает поддержку Android и т.д. Adobe по-прежнему обновляет и открывает источники этих частей флеш-плеера, поэтому это хороший текущий и официальный материал.

Пока я нахожусь в этом, это может также представлять интерес: http://code.google.com/p/redtamarin/. Это разветвленная (и довольно зрелая) версия AVM и может использоваться для написания сценария на стороне сервера. Аккуратный материал и тонна информации, которая дает представление о работе AVM, поэтому я думал, что включу его тоже.

Ответ 2

Это поведение задокументировано (выделено мной):

Цикл for..in выполняет итерацию через свойства объекта или элементы массива. Например, вы можете использовать цикл for..in для итерации свойств общего объекта (свойства объекта не сохраняются в каком-либо конкретном порядке, поэтому свойства могут появляться в кажущемся случайном порядке)

Как сохраняются и извлекаются свойства, это детализация реализации, которая не рассматривается в документации. Однако, как отмечает ToddBFisher в комментарии, структура данных, обычно используемая для реализации ассоциативных массивов, представляет собой хеш-таблицу . Он даже упоминал в эту страницу об ассоциативных массивах в AS3, и если вы проверите AVM-код как показанный Ascension Systems, вы найдете именно такую ​​реализацию. Как описано, в типичных хеш-таблицах нет понятия порядка или сортировки.

Я не верю, что есть способ получить доступ к свойствам в определенном порядке, если вы каким-то образом не сохранили этот порядок.