Страницы

Поиск по вопросам

воскресенье, 15 марта 2020 г.

Обращение к объекту, как к массиву

#javascript #объекты #index


Есть ли простой способ обратиться к ключу объекта по его индексу? Может в Underscore
есть магические методы?

Вопрос возник на фоне такой задачи. Есть объект:

plane: {
    432: {
        columns: {
            543: {
                name: 'lolo'
            },
            984: {
                name: 'lala'
            },
            ...
        }
    },
    ...
}


Где среди n-го количества plane, и n-го количества column нужно выбрать первый plane
и первый column внутри него.

Как сделать это проще всего?
    


Ответы

Ответ 1



Хотя ES6 обеспечивает определённый порядок ключей при обходе, гораздо правильнее и удобнее использовать массив, положив тот ключ внутрь объекта, например, в поле id. Но если уж очень хочется, то можно сделать так (как-нибудь сократив название): Object.prototype.getByKeyIndex = function (i) { var key = Object.keys(this)[i]; return key && this[key]; } Тогда на объекте из вопроса будет такое: plane.getByKeyIndex(0).columns.getByKeyIndex(1).name // "lala" Вроде, более-менее нормально выглядит. Ключ сохраняется в переменную и проверяется, чтобы в таком варианте получилось undefined: ({ undefined: 42 }).getByKeyIndex(256) Я новичок и хочу у Вас спросить - хорошо ли изменять прототип нативных объектов? Что будет если я добавлю метод, а после кто-то другой тоже Ваш ответ увидит и решит добавить свой, но с таким же методом? В большинстве случаев изменять прототип Object'а не очень хорошо. Но для защиты от прототипных свойств принято фильтровать for-in через hasOwnProperty. Другой вариант - добавлять в прототип не так, как это сделал я, а через скрытое свойство, чтобы оно не перебиралось. Если двое добавили одинаковое свойство, то одно из них перезапишет другое. По идее, последнее добавленное должно перезаписать предыдущее, но можно пошаманить с readonly, чтобы осталось более раннее. В любом случае, такая ситуация заведомо плохая и лучше в неё не попадать. Если двое добавят одну и ту же функцию под разными именами, то будет две функции. Тут вроде всё очевидно и вопросов вызывать не должно. Что касается того, стоит ли изменять прототип. Если это изменение упростит половину кода, то, на мой взгляд, это оправдано. Если же это делается ради одной функции, то, скорее всего, нет. Для любых глобальных изменений стоит проявлять разумность и осторожность.

Ответ 2



Object.keys(obj)[index] например, где obj - объект в котором мы ищем. Не вполне ослоустойчиво, будет работать в IE 9+. Можно использовать _.keys(obj)[index] из underscore, это все сократит на пару символов =). Кстати я не уверен, что лексикографический (да и вообще какой-то) порядок ключей нам гарантирован при этом, скорее всего массив ключей надо дополнительно сортировать.

Ответ 3



TL;DR: Порядок ключей в объекте JS не гарантируется. Для сохранения порядка лучше юзать массив. Из личного опыта: Браузеры стараются придерживаться того порядка полей, в котором они были определены. Но на это рассчитывать не стоит. Например, при общении с сервером через WebApi порядок может сбится. Практический пример: в python объекты JSON преобразуется в словарь dict. А в нем уж точно порядок полей не сохраняется и может поменятся произвольно при сериализации обратно в JSON. Объекты JS - это хеш-таблицы, т.е. пары ключ-значение. Порядок пар в такой структуре данных не имеет значения. Они удобны для обращения по ключу со сложностью O(1) (т.е. вне зависимости от числа этих пар). Из спецификации: Порядок ключей в Object.keys такой же, как при перечислении через for...in. В описании же for...in сказано in arbitrary order, что значит "в произвольном порядке". Косвенные признаки: В консоли Chrome и во время отладки свойства идут в алфавитном порядке. А при проходе через for...in - в порядке определения. То, что хром так пренебрежительно относится к порядку ключей объекта, говорит о том, что он не имеет никакого значения. В JS нет никаких явных способов изменить порядок полей. Или хотя бы вставить поле в середину объекта.

Ответ 4



var key = function(obj, n) { return obj[Object.keys(obj)[n]]; } key(key(d, 0), 0); Если вы хотите порядок сохранять, то передалайте на массивы: plane: [{ 432: { columns: [{ 543: { name: 'lolo' }, 984: { name: 'lala' }, ... }, ... ] }, ... }, ... ]

Комментариев нет:

Отправить комментарий