У меня есть вложенная структура данных, содержащая объекты и массивы. Как я могу извлечь информацию, то есть получить доступ к определенным или множественным значениям (или ключам)?
Например:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
Как я могу получить доступ name
ко второму пункту в items
?
javascript
arrays
object
nested
data-manipulation
Феликс Клинг
источник
источник
Ответы:
прелиминарии
JavaScript имеет только один тип данных, который может содержать несколько значений: Object . Массив представляет собой особую форму объекта.
(Обычный) Объекты имеют вид
Массивы имеют форму
И массивы, и объекты предоставляют
key -> value
структуру. Ключи в массиве должны быть числовыми, тогда как любая строка может использоваться в качестве ключа в объектах. Пары ключ-значение также называются «свойствами» .Свойства могут быть доступны либо с использованием точечной нотации
или обозначение в скобках , если имя свойства не будет допустимым именем идентификатора JavaScript [spec] , или имя является значением переменной:
По этой причине доступ к элементам массива возможен только в скобках:
Подождите ... как насчет JSON?
JSON - это текстовое представление данных, как XML, YAML, CSV и другие. Чтобы работать с такими данными, их сначала нужно преобразовать в типы данных JavaScript, то есть массивы и объекты (и как работать с ними только что объяснено). Как разобрать JSON объясняется в вопросе Parse JSON в JavaScript? ,
Дальнейшее чтение материала
Доступ к массивам и объектам является фундаментальным знанием JavaScript, и поэтому желательно прочитать руководство по MDN JavaScript , особенно разделы.
Доступ к вложенным структурам данных
Вложенная структура данных - это массив или объект, который ссылается на другие массивы или объекты, т.е. его значения являются массивами или объектами. К таким структурам можно получить доступ, последовательно применяя точечные или скобочные обозначения.
Вот пример:
Давайте предположим, что мы хотим получить доступ
name
ко второму элементу.Вот как мы можем сделать это шаг за шагом:
Как мы видим
data
, это объект, следовательно, мы можем получить доступ к его свойствам, используя точечную запись.items
Свойство получено следующим образом :Значение является массивом, для доступа ко второму элементу мы должны использовать скобочную запись:
Это значение является объектом, и мы снова используем точечную запись для доступа к
name
свойству. Итак, мы в итоге получаем:В качестве альтернативы, мы могли бы использовать скобочную запись для любого из свойств, особенно если имя содержит символы, которые сделали бы его недопустимым для использования точечной нотации:
Я пытаюсь получить доступ к собственности, но я получаю только
undefined
обратно?В большинстве случаев у
undefined
объекта / массива просто нет свойства с таким именем.Используйте
console.log
илиconsole.dir
и проверьте структуру объекта / массива. Свойство, к которому вы пытаетесь получить доступ, может быть фактически определено для вложенного объекта / массива.Что если имена свойств являются динамическими, и я не знаю их заранее?
Если имена свойств неизвестны или мы хотим получить доступ ко всем свойствам объекта / элементов массива, мы можем использовать цикл
for...in
[MDN] для объектов и циклfor
[MDN] для массивов для перебора всех свойств / элементов.Объекты
Чтобы перебрать все свойства
data
, мы можем перебрать объект так:В зависимости от того, откуда берется объект (и что вы хотите сделать), вам, возможно, придется проверять на каждой итерации, является ли свойство действительно свойством объекта или унаследованным свойством. Вы можете сделать это с
Object#hasOwnProperty
[MDN] .В качестве альтернативы
for...in
withhasOwnProperty
вы можете использоватьObject.keys
[MDN] для получения массива имен свойств :Массивы
Чтобы перебрать все элементы
data.items
массива , мы используемfor
цикл:Можно также использовать
for...in
для итерации массивов, но есть причины, по которым этого следует избегать: почему «for (var item in list)» с массивами считается плохой практикой в JavaScript? ,С увеличением поддержки браузером ECMAScript 5, метод массива
forEach
[MDN] также становится интересной альтернативой:В средах, поддерживающих ES2015 (ES6), вы также можете использовать цикл [MDN] , который работает не только для массивов, но и для любых итераций :
for...of
В каждой итерации,
for...of
непосредственно дает нам следующий элемент итерируемого, нет «индекса» для доступа или использования.Что если «глубина» структуры данных мне неизвестна?
В дополнение к неизвестным ключам также может быть неизвестна «глубина» структуры данных (то есть, сколько вложенных объектов). Как получить доступ к глубоко вложенным свойствам, обычно зависит от точной структуры данных.
Но если структура данных содержит повторяющиеся узоры, например , представление двоичного дерева, то решение , как правило , включает в рекурсивно [Wikipedia] доступ для каждого уровня структуры данных.
Вот пример, чтобы получить первый листовой узел двоичного дерева:
Показать фрагмент кода
Более общий способ получить доступ к вложенной структуре данных с неизвестными ключами и глубиной - это проверить тип значения и действовать соответственно.
Вот пример, который добавляет все примитивные значения внутри вложенной структуры данных в массив (при условии, что он не содержит никаких функций). Если мы сталкиваемся с объектом (или массивом), мы просто
toArray
снова вызываем это значение (рекурсивный вызов).Показать фрагмент кода
Помощники
Поскольку структура сложного объекта или массива не обязательно очевидна, мы можем проверять значение на каждом шаге, чтобы решить, как двигаться дальше.
console.log
[MDN] иconsole.dir
[MDN] помогают нам в этом. Например (вывод консоли Chrome):Здесь мы видим, что
data.items
это массив с двумя элементами, которые оба являются объектами. В консоли Chrome объекты могут быть даже расширены и проверены немедленно.Это говорит нам о том, что
data.items[1]
это объект, и после его расширения мы видим, что у него есть три свойстваid
,name
и__proto__
. Последнее является внутренним свойством, используемым для цепочки прототипов объекта. Тем не менее, цепочка прототипов и наследование выходят за рамки этого ответа.источник
let object = {a: 1, b: 2, c: { a: 3, b: 4 }};
, это возвращает массив, содержащий массив для каждого вложенного объекта, в этом случае[ 1, 2, [ 3, 4 ] ]
не лучше ли использовать concat в рекурсивном вызове вместо push? (требующий, чтобы результат был изменчивым)Вы можете получить к нему доступ таким образом
или
Оба пути равны.
источник
В случае, если вы пытаетесь получить доступ
item
к структуре примера с помощьюid
илиname
, не зная его положения в массиве, самый простой способ сделать это - использовать библиотеку underscore.js :Исходя из моего опыта, использование функций более высокого порядка вместо циклов
for
илиfor..in
приводит к коду, который легче рассуждать и, следовательно, более легок в обслуживании.Просто мои 2 цента.
источник
Объекты и массивы имеют много встроенных методов, которые могут помочь вам в обработке данных.
Примечание: во многих примерах я использую функции стрелок . Они похожи на выражения функций , но они связывают
this
значение лексически.Object.keys()
,Object.values()
(ES 2017) иObject.entries()
(ES 2017)Object.keys()
возвращает массив ключей объекта,Object.values()
возвращает массив значений объекта иObject.entries()
возвращает массив ключей объекта и соответствующих значений в формате[key, value]
.Object.entries()
с циклом for и деструктурирующим назначениемОчень удобно итерировать результат
Object.entries()
с помощью цикла for и назначения деструктурирования .Цикл For-of позволяет перебирать элементы массива. Синтаксис
for (const element of array)
(мы можем заменитьconst
наvar
илиlet
, но лучше использовать,const
если мы не собираемся изменятьelement
).Разрушающее присваивание позволяет извлекать значения из массива или объекта и назначать их переменным. В данном случае
const [key, value]
означает, что вместо присвоения[key, value]
массиваelement
мы присваиваем первый элемент этого массива,key
а второй -value
. Это эквивалентно этому:Как видите, деструктуризация делает это намного проще.
Array.prototype.every()
а такжеArray.prototype.some()
В
every()
метод возвращает значение,true
если указанная функция обратного вызова возвращаетtrue
для каждого элемента массива. Вsome()
метод возвращает значение,true
если указанная функция обратного вызова возвращаетtrue
для некоторого элемента ( по крайней мере , одной).Array.prototype.find()
а такжеArray.prototype.filter()
Эти
find()
методы возвращают первый элемент , который удовлетворяет условия функции обратного вызова.filter()
Метод возвращает массив всех элементов, удовлетворяющие условия функции обратного вызова.Array.prototype.map()
map()
Метод возвращает массив с результатами вызова функции обратного вызова при условии на элементах массива.Array.prototype.reduce()
reduce()
Метод уменьшает массив к единственному значению, вызвав предоставленную функцию обратного вызова с двумя элементами.reduce()
Метод принимает необязательный второй параметр, который представляет собой первоначальное значение. Это полезно, когда массив, к которому выreduce()
обращаетесь, может содержать ноль или один элемент. Например, если мы хотим создать функцию,sum()
которая принимает массив в качестве аргумента и возвращает сумму всех элементов, мы могли бы написать это так:источник
Object.keys(data["items"]).forEach(function(key) { console.log(data["items"][key].id); console.log(data["items"][key].name); });
Иногда доступ к вложенному объекту с использованием строки может быть желательным. Простой подход - это, например, первый уровень
Но это часто не так со сложным JSON. Поскольку json становится все более сложным, подходы для нахождения значений внутри json также становятся сложными. Рекурсивный подход для навигации по json лучше всего, и то, как эта рекурсия будет использоваться, будет зависеть от типа данных, которые ищутся. Если используются условные операторы, поиск json может быть хорошим инструментом для использования.
Если доступ к свойству уже известен, но путь сложен, например, в этом объекте
И вы знаете, что хотите получить первый результат массива в объекте, возможно, вы хотели бы использовать
Однако это вызовет исключение, поскольку у объекта с таким именем нет свойства. Решение, чтобы иметь возможность использовать это было бы, чтобы сгладить аспект дерева объекта. Это можно сделать рекурсивно.
Теперь сложный объект можно сплющить
Вот
jsFiddle Demo
этот подход используется.источник
obj["arr[0].name"]
вместоobj.arr[0].name
? Вам вряд ли нужно / нужно иметь дело со сплющенными объектами, за исключением сериализации.Этот вопрос довольно старый, так как современное обновление. С началом ES2015 есть альтернативы, чтобы получить данные, которые вам нужны. Теперь есть функция, называемая деструктуризацией объектов, для доступа к вложенным объектам.
В приведенном выше примере создается переменная, вызываемая
secondName
изname
ключа из массива, который называетсяitems
одинокий,,
пропустить первый объект в массиве.Примечательно, что в этом примере это, вероятно, излишне, так как простой доступ к массиву легче читать, но он полезен при разделении объектов в целом.
Это очень краткое введение в ваш конкретный вариант использования, деструктуризация может быть необычным синтаксисом, к которому нужно сначала привыкнуть. Я бы порекомендовал прочитать документацию Mozilla's Destructuring Assignment, чтобы узнать больше.
источник
Чтобы получить доступ к вложенному атрибуту, необходимо указать его имя, а затем выполнить поиск по объекту.
Если вы уже знаете точный путь, вы можете жестко закодировать его в своем скрипте следующим образом:
это тоже работает -
Когда вы не знаете точного имени заранее, или пользователь предоставляет вам имя. Затем требуется динамический поиск по структуре данных. Некоторые предположили, что поиск может быть выполнен с использованием
for
цикла, но есть очень простой способ пройти через путьArray.reduce
.Путь - это способ сказать: сначала возьмите объект с ключом
items
, который оказывается массивом. Затем возьмите1
-st элемент (0 индексных массивов). Последний возьмите объект с ключомname
в этом элементе массива, который является строкойbar
.Если у вас очень длинный путь, вы можете даже использовать,
String.split
чтобы сделать все это проще -Это просто обычный JavaScript, без использования сторонних библиотек, таких как jQuery или lodash.
источник
или
В основном, используйте точку между каждым потомком, который разворачивается под ним, и когда у вас есть имена объектов, состоящие из двух строк, вы должны использовать нотацию ["obj Name"]. В противном случае достаточно точки;
Источник: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects
добавим, что доступ к вложенным массивам будет происходить так:
Источник: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays/
Еще один более полезный документ, описывающий ситуацию выше: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation
Доступ к собственности с помощью точечного хождения: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation
источник
Вы можете использовать
lodash _get
функцию:источник
Использование JSONPath будет одним из наиболее гибких решений, если вы захотите включить библиотеку: https://github.com/s3u/JSONPath (узел и браузер)
Для вашего случая использования путь json будет:
так:
источник
На всякий случай, если кто-нибудь посетит этот вопрос в 2017 году или позже и ищет легкий для запоминания способ, вот подробный пост в блоге о доступе к вложенным объектам в JavaScript без обмана со стороны
Невозможно прочитать свойство 'foo' с неопределенной ошибкой
1. Шаблон доступа к вложенным объектам Оливера Стила
Самый простой и чистый способ - использовать шаблон доступа к вложенным объектам Оливера Стила.
С этим обозначением вы никогда не столкнетесь с
Невозможно прочитать свойство 'имя' из неопределенного .
Вы в основном проверяете, существует ли пользователь, если нет, вы создаете пустой объект на лету. Таким образом, ключ следующего уровня будет всегда доступен из существующего объекта или пустого объекта , но никогда из неопределенного.
2. Доступ к вложенным объектам с помощью Array Reduce
Чтобы иметь доступ к вложенным массивам, вы можете написать свой собственный массив execute.
Существует также превосходная обработка типов минимальной библиотеки типов, которая сделает все это за вас.
источник
((user || {}).address || new Array(3))[1].name
...[1].bar
это приведет к ошибке, если элемент1
не существует. Но это также касается случая,....foo.bar
еслиfoo
не существовало. Вы также должны «охранять» доступ1
, точно так же, как вы «охраняете» любой другой доступ к собственности. Массив - это просто объект. «Элемент массива» - это просто свойство. Правильно это будет применено(((user || {}).address || {})[1] || {}).name
.Я предпочитаю JQuery. Это чище и легко читается.
источник
Доступ к динамически многоуровневому объекту.
Рабочая скрипка: https://jsfiddle.net/andreitodorut/3mws3kjL/
источник
Если вы ищете один или несколько объектов, которые соответствуют определенным критериям, у вас есть несколько вариантов, используя query-js
Там также есть
single
иsingleOrDefault
они работают так же, какfirst
иfirstOrDefault
соответственно. Единственное отличие состоит в том , что они будут бросать , если более чем один матч найден.для дальнейшего объяснения query-js вы можете начать с этого поста
источник
Подчеркнуть JS Way
Это библиотека JavaScript, которая предоставляет целый набор полезных
functional programming
помощников без расширения каких-либо встроенных объектов.Решение:
источник
Старый вопрос, но как никто не упомянул lodash (только подчеркивание).
Если вы уже используете lodash в своем проекте, я думаю, элегантный способ сделать это в сложном примере:
Опция 1
такой же как:
Опция 2
Разница между первым и вторым вариантом заключается в том, что в параметре 1, если у вас отсутствует одно из (отсутствующих) свойств в пути, вы не получите ошибку, он возвращает вам третий параметр.
Для фильтра массива lodash есть,
_.find()
но я бы лучше использовал обычныйfilter()
. Но я все еще думаю, что вышеупомянутый метод_.get()
очень полезен при работе с действительно сложными данными. В прошлом я сталкивался с действительно сложными API, и это было удобно!Я надеюсь, что это может быть полезно для тех, кто ищет варианты для манипулирования действительно сложными данными, которые подразумевает заголовок.
источник
Я не думаю, что спрашивающий касается только вложенного объекта одного уровня, поэтому я представляю следующую демонстрацию, чтобы продемонстрировать, как получить доступ к узлу глубоко вложенного объекта json. Хорошо, давайте найдем узел с идентификатором '5'.
источник
Вы можете использовать синтаксис
jsonObject.key
для доступа к значению. И если вы хотите получить доступ к значению из массива, вы можете использовать синтаксисjsonObjectArray[index].key
.Вот примеры кода для доступа к различным значениям, чтобы дать вам идею.
источник
Динамический подход
В приведенной ниже
deep(data,key)
функции вы можете использовать произвольнуюkey
строку - в вашем случаеitems[1].name
(вы можете использовать запись массива[i]
на любом уровне) - если ключ недействителен, то возвращается undefined.Показать фрагмент кода
источник
Питонический, рекурсивный и функциональный подход для раскрытия произвольных деревьев JSON:
где данные - это список Python (анализируется из текстовой строки JSON):
источник
Функция grep в jQuery позволяет фильтровать массив:
источник
источник
В 2020 году вы можете использовать @ babel / plugin-Предложение-опционально-цепочки, это очень легко получить доступ к вложенным значениям в объекте.
https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
https://github.com/tc39/proposal-optional-chaining
источник
Мой
stringdata
идет из файла PHP, но все же, я указываю здесь, вvar
. Когда я непосредственно беру свой JSON вobj
него, ничего не покажет, поэтому я положил свой файл JSON какvar obj=JSON.parse(stringdata);
так что после этого я получаюmessage
obj и показываю в окне предупреждения, затем я получаюdata
массив json и сохраняю его в одну переменную,ArrObj
затем я читаю первый объект этого массива со значением ключа, как этоArrObj[0].id
источник
stringjson
это не строка.Использование lodash было бы хорошим решением
Пример:
источник