我有一个包含对象和数组的嵌套数据结构。我如何提取信息,即访问一个特定的或多个值(或键)?
例如:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
我如何访问项目中的第二个项目的名称?
我有一个包含对象和数组的嵌套数据结构。我如何提取信息,即访问一个特定的或多个值(或键)?
例如:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
我如何访问项目中的第二个项目的名称?
当前回答
要访问嵌套属性,需要指定其名称,然后搜索对象。
如果你已经知道确切的路径,那么你可以像这样在你的脚本中硬编码它:
data['items'][1]['name']
这些也有用——
data.items[1].name
data['items'][1].name
data.items[1]['name']
如果您事先不知道确切的名称,或者用户是为您提供名称的人。然后需要动态搜索数据结构。有些人建议可以使用for循环来完成搜索,但是有一种非常简单的方法可以使用Array.reduce遍历路径。
const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }
const path = [ 'items', '1', 'name']
let result = path.reduce((a,v) => a[v], data)
路径的意思是:首先获取带有关键项的对象,它恰好是一个数组。然后取第1个元素(0个索引数组)。最后取该数组元素中键名的对象,恰好是字符串bar。
如果路径很长,甚至可以使用String。分开让这一切更容易-
'items.1.name'.split('.').reduce((a,v) => a[v], data)
这只是简单的JavaScript,没有使用任何第三方库,如jQuery或lodash。
其他回答
python式、递归式和函数式方法来分解任意JSON树:
handlers = {
list: iterate,
dict: delve,
str: emit_li,
float: emit_li,
}
def emit_li(stuff, strong=False):
emission = '<li><strong>%s</strong></li>' if strong else '<li>%s</li>'
print(emission % stuff)
def iterate(a_list):
print('<ul>')
map(unravel, a_list)
print('</ul>')
def delve(a_dict):
print('<ul>')
for key, value in a_dict.items():
emit_li(key, strong=True)
unravel(value)
print('</ul>')
def unravel(structure):
h = handlers[type(structure)]
return h(structure)
unravel(data)
其中data是python列表(从JSON文本字符串解析而来):
data = [
{'data': {'customKey1': 'customValue1',
'customKey2': {'customSubKey1': {'customSubSubKey1': 'keyvalue'}}},
'geometry': {'location': {'lat': 37.3860517, 'lng': -122.0838511},
'viewport': {'northeast': {'lat': 37.4508789,
'lng': -122.0446721},
'southwest': {'lat': 37.3567599,
'lng': -122.1178619}}},
'name': 'Mountain View',
'scope': 'GOOGLE',
'types': ['locality', 'political']}
]
有时,使用字符串访问嵌套对象是可取的。例如,最简单的方法是第一级
var obj = { hello: "world" };
var key = "hello";
alert(obj[key]);//world
但复杂的json通常不是这样。随着json变得越来越复杂,在json中查找值的方法也变得越来越复杂。导航json的递归方法是最好的,如何利用递归取决于要搜索的数据类型。如果涉及到条件语句,json搜索可能是一个很好的工具。
如果已经知道要访问的属性,但是路径很复杂,例如在这个对象中
var obj = {
arr: [
{ id: 1, name: "larry" },
{ id: 2, name: "curly" },
{ id: 3, name: "moe" }
]
};
你知道你想要得到对象中数组的第一个结果,也许你想使用
var moe = obj["arr[0].name"];
然而,这将导致一个异常,因为对象没有该名称的属性。能够使用这种方法的解决方案是将对象的树形面平直。这可以递归完成。
function flatten(obj){
var root = {};
(function tree(obj, index){
var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
for(var key in obj){
if(!obj.hasOwnProperty(key))continue;
root[index+key+suffix] = obj[key];
if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");
}
})(obj,"");
return root;
}
现在,这个复杂的物体可以被平面化
var obj = previous definition;
var flat = flatten(obj);
var moe = flat["arr[0].name"];//moe
下面是使用这种方法的jsFiddle演示。
// const path = 'info.value[0].item'
// const obj = { info: { value: [ { item: 'it works!' } ], randominfo: 3 } }
// getValue(path, obj)
export const getValue = ( path , obj) => {
const newPath = path.replace(/\]/g, "")
const arrayPath = newPath.split(/[\[\.]+/) || newPath;
const final = arrayPath.reduce( (obj, k) => obj ? obj[k] : obj, obj)
return final;
}
要访问嵌套属性,需要指定其名称,然后搜索对象。
如果你已经知道确切的路径,那么你可以像这样在你的脚本中硬编码它:
data['items'][1]['name']
这些也有用——
data.items[1].name
data['items'][1].name
data.items[1]['name']
如果您事先不知道确切的名称,或者用户是为您提供名称的人。然后需要动态搜索数据结构。有些人建议可以使用for循环来完成搜索,但是有一种非常简单的方法可以使用Array.reduce遍历路径。
const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }
const path = [ 'items', '1', 'name']
let result = path.reduce((a,v) => a[v], data)
路径的意思是:首先获取带有关键项的对象,它恰好是一个数组。然后取第1个元素(0个索引数组)。最后取该数组元素中键名的对象,恰好是字符串bar。
如果路径很长,甚至可以使用String。分开让这一切更容易-
'items.1.name'.split('.').reduce((a,v) => a[v], data)
这只是简单的JavaScript,没有使用任何第三方库,如jQuery或lodash。
动态访问多级对象。
var obj = {
name: "john doe",
subobj: {
subsubobj: {
names: "I am sub sub obj"
}
}
};
var level = "subobj.subsubobj.names";
level = level.split(".");
var currentObjState = obj;
for (var i = 0; i < level.length; i++) {
currentObjState = currentObjState[level[i]];
}
console.log(currentObjState);
工作提琴:https://jsfiddle.net/andreitodorut/3mws3kjL/