javascript - Access / process (nested) objects, arrays or JSON -
i have (nested) data structure containing objects , arrays. how can extract information, i.e. access specific or multiple values (or keys)?
for example:
var data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };
how access name
of second item in items
?
preliminaries
javascript has 1 data type can contain multiple values: object. array special form of object.
(plain) objects have form
{key: value, key: value, ...}
arrays have form
[value, value, ...]
both arrays , objects expose key -> value
structure. keys in array must numeric, whereas string can used key in objects. key-value pairs called "properties".
properties can accessed either using dot notation
const value = obj.someproperty;
or bracket notation, if property name not valid javascript identifier name [spec], or name value of variable:
// space not valid character in identifier names const value = obj["some property"]; // property name variable const name = "some property"; const value = obj[name];
for reason, array elements can accessed using bracket notation:
const value = arr[5]; // arr.5 syntax error // property name / index variable const x = 5; const value = arr[x];
wait... json?
json textual representation of data, xml, yaml, csv, , others. work such data, first has converted javascript data types, i.e. arrays , objects (and how work explained). how parse json explained in question parse json in javascript? .
further reading material
how access arrays , objects fundamental javascript knowledge , therefore advisable read mdn javascript guide, sections
accessing nested data structures
a nested data structure array or object refers other arrays or objects, i.e. values arrays or objects. such structures can accessed consecutively applying dot or bracket notation.
here example:
const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };
let's assume want access name
of second item.
here how can step-by-step:
as can see data
object, hence can access properties using dot notation. items
property accessed follows:
data.items
the value array, access second element, have use bracket notation:
data.items[1]
this value object , use dot notation again access name
property. get:
const item_name = data.items[1].name;
alternatively, have used bracket notation of properties, if name contained characters have made invalid dot notation usage:
const item_name = data['items'][1]['name'];
i'm trying access property undefined
back?
most of time when getting undefined
, object/array doesn't have property name.
const foo = {bar: {baz: 42}}; console.log(foo.baz); // undefined
use console.log
or console.dir
, inspect structure of object / array. property trying access might defined on nested object / array.
console.log(foo.bar.baz); // 42
what if property names dynamic , don't know them beforehand?
if property names unknown or want access properties of object / elements of array, can use for...in
[mdn] loop objects , for
[mdn] loop arrays iterate on properties / elements.
objects
to iterate on properties of data
, can iterate on object so:
for (const prop in data) { // `prop` contains name of each property, i.e. `'code'` or `'items'` // consequently, `data[prop]` refers value of each property, i.e. // either `42` or array }
depending on object comes (and want do), might have test in each iteration whether property property of object, or inherited property. can object#hasownproperty
[mdn].
as alternative for...in
hasownproperty
, can use object.keys
[mdn] array of property names:
object.keys(data).foreach(function(prop) { // `prop` property name // `data[prop]` property value });
arrays
to iterate on elements of data.items
array, use for
loop:
for(let = 0, l = data.items.length; < l; i++) { // `i` take on values `0`, `1`, `2`,..., i.e. in each iteration // can access next element in array `data.items[i]`, example: // // var obj = data.items[i]; // // since each element object (in our example), // can access objects properties `obj.id` , `obj.name`. // use `data.items[i].id`. }
one use for...in
iterate on arrays, there reasons why should avoided: why 'for(var item in list)' arrays considered bad practice in javascript?.
with increasing browser support of ecmascript 5, array method foreach
[mdn] becomes interesting alternative well:
data.items.foreach(function(value, index, array) { // callback executed each element in array. // `value` element (equivalent `array[index]`) // `index` index of element in array // `array` reference array (i.e. `data.items` in case) });
in environments supporting es2015 (es6), can use for...of
[mdn] loop, not works arrays, iterable:
for (const item of data.items) { // `item` array element, **not** index }
in each iteration, for...of
directly gives next element of iterable, there no "index" access or use.
what if "depth" of data structure unknown me?
in addition unknown keys, "depth" of data structure (i.e. how many nested objects) has, might unknown well. how access nested properties depends on exact data structure.
but if data structure contains repeating patterns, e.g. representation of binary tree, solution typically includes recursively [wikipedia] access each level of data structure.
here example first leaf node of binary tree:
function getleaf(node) { if (node.leftchild) { return getleaf(node.leftchild); // <- recursive call } else if (node.rightchild) { return getleaf(node.rightchild); // <- recursive call } else { // node must leaf node return node; } } const first_leaf = getleaf(root);
const root = { leftchild: { leftchild: { leftchild: null, rightchild: null, data: 42 }, rightchild: { leftchild: null, rightchild: null, data: 5 } }, rightchild: { leftchild: { leftchild: null, rightchild: null, data: 6 }, rightchild: { leftchild: null, rightchild: null, data: 7 } } }; function getleaf(node) { if (node.leftchild) { return getleaf(node.leftchild); } else if (node.rightchild) { return getleaf(node.rightchild); } else { // node must leaf node return node; } } console.log(getleaf(root).data);
a more generic way access nested data structure unknown keys , depth test type of value , act accordingly.
here example adds primitive values inside nested data structure array (assuming not contain functions). if encounter object (or array) call toarray
again on value (recursive call).
function toarray(obj) { const result = []; (const prop in obj) { const value = obj[prop]; if (typeof value === 'object') { result.push(toarray(value)); // <- recursive call } else { result.push(value); } } return result; }
const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }; function toarray(obj) { const result = []; (const prop in obj) { const value = obj[prop]; if (typeof value === 'object') { result.push(toarray(value)); } else { result.push(value); } } return result; } console.log(toarray(data));
helpers
since structure of complex object or array not obvious, can inspect value @ each step decide how move further. console.log
[mdn] , console.dir
[mdn] doing this. example (output of chrome console):
> console.log(data.items) [ object, object ]
here see that data.items
array 2 elements both objects. in chrome console objects can expanded , inspected immediately.
> console.log(data.items[1]) object id: 2 name: "bar" __proto__: object
this tells data.items[1]
object, , after expanding see has 3 properties, id
, name
, __proto__
. latter internal property used prototype chain of object. prototype chain , inheritance out of scope answer, though.