Ответ 1
Ваш avatars
не является массивом, это просто объект:
avatars = {};
поэтому не определен порядок для его элементов:
Механика и порядок перечисления свойств (шаг 6.a в первом алгоритме, шаг 7.a во втором) не указывается.
Если реализация определяет определенный порядок перечисления для оператора for-in, тот же порядок перечисления должен использоваться для упорядочения элементов списка на шаге 3 этого алгоритма.
Вы также можете проверить раздел 8.6, чтобы узнать, есть ли упоминание о порядке свойств объекта. Единственное требование для упорядочения свойств объекта состоит в том, что если реализация определяет порядок где угодно, тогда он должен использовать тот же порядок везде, но большой, если. Большинство реализаций, вероятно, используют порядок вставки для ключей объектов, но я не могу найти что-либо, что требует от них (я был бы признателен за комментарий, если кто-нибудь может указать что-либо в спецификациях, которые определяют какой-либо конкретный порядок ключей объекта).
Тем не менее, Underscore sortBy
в основном представляет собой Schwartzian Transform в сочетании со стандартным JavaScript sort
и Underscore pluck
, чтобы развернуть обертки для заметок Schwartzian Transform; pluck
возвращает массив, поэтому sortBy
также возвращает массив. Следовательно, ваш окончательный вызов _.keys(avatars)
фактически вызывает _.keys
в массиве; ключи массива (перечислимые свойства AKA) - это индексы массива, а последовательные целые числа начинаются с нуля.
Вы используете неправильную структуру данных. Если вам нужен разреженный массив, но также нужно манипулировать им, как массив (т.е. Сортировать его), тогда вы должны поместить индексы внутри объектов и использовать обычный массив и pluck
вместо keys
:
var avatars = [
{idx: 102, userInfo: {buddy_name: 'Avatar102', is_online: 1}},
{idx: 100, userInfo: {buddy_name: 'Avatar100', is_online: 1}},
{idx: 101, userInfo: {buddy_name: 'Avatar101', is_online: 1}}
];
console.log(_(avatars).pluck('idx'));
avatars = _(avatars).sortBy(function(avatar) {
return avatar.userInfo.buddy_name.toLowerCase();
});
console.log(_(avatars).pluck('idx'));
Демо: http://jsfiddle.net/ambiguous/UCWL2/
Если вам также нужен быстрый доступ к idx
, вы можете настроить параллельный объект для прямого доступа idx
:
var avatars_by_idx = { };
for(var i = 0; i < avatars.length; ++i)
avatars_by_idx[avatars[i].idx] = avatars[i];
Затем avatars_by_idx
предоставляет прямой доступ, который вы ищете. Конечно, вам нужно будет синхронизировать avatars
и avatars_by_idx
, но это не так сложно, если вы спрячете их как за объектом.