我有一个包含对象和数组的嵌套数据结构。我如何提取信息,即访问一个特定的或多个值(或键)?
例如:
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'
}]
};
我如何访问项目中的第二个项目的名称?
当前回答
// 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;
}
其他回答
老问题,但没有人提到lodash(只是下划线)。
如果你已经在你的项目中使用lodash,我认为在一个复杂的例子中有一种优雅的方法:
选择1
_.get(response, ['output', 'fund', 'data', '0', 'children', '0', 'group', 'myValue'], '')
一样:
选择2
response.output.fund.data[0].children[0].group.myValue
第一个选项和第二个选项之间的区别是,在Opt 1中,如果你在路径中缺少一个属性(未定义),你不会得到错误,它会返回第三个参数。
对于数组过滤器,lodash有_.find(),但我宁愿使用常规的filter()。但我仍然认为上面的方法_.get()在处理非常复杂的数据时非常有用。我在过去遇到过非常复杂的api,它很方便!
我希望它能对那些正在寻找操作标题所暗示的真正复杂数据的选项的人有用。
解释很简单:
Var数据= { 42岁的代码: 项目:[{ id: 1、 名称:“foo” }, { id: 2 名称:“酒吧” }) }; /* 1. “data”对象包含“items”对象*/ console.log(数据); /* 2. ' items '对象包含两个对象作为元素的数组*/ console.log (data.items); /* 3.你需要数组的第二个元素-从'[0,1]' */中的' 1 ' console.log (data.items [1]); /* 4. 你需要第二个对象的' name '属性的值-数组的元素)*/ console.log (data.items [1] . name);
对象和数组有很多内置方法,可以帮助您处理数据。
注意:在很多例子中,我都使用了箭头函数。它们类似于函数表达式,但是它们在词法上绑定this值。
Object.keys(), Object.values() (ES 2017)和Object.entries() (ES 2017)
object .keys()返回对象键的数组,object .values()返回对象值的数组,object .entries()返回格式为[key, value]的对象键和相应值的数组。
Const obj = { 答:1 b: 2 c: 3 } console.log(Object.keys(obj)) // ['a', 'b', 'c'] console.log(Object.values(obj)) // [1,2,3] console.log (Object.entries (obj)) / / [[a, 1] [b 2], [' c ', 3]]
Object.entries()带有for-of循环和析构赋值
Const obj = { 答:1 b: 2 c: 3 } for (const [key, value] of Object.entries(obj)) { Console.log (' key: ${key}, value: ${value} ') }
使用for-of循环和解构赋值迭代Object.entries()的结果非常方便。
For-of循环允许迭代数组元素。语法为(const element of array)(我们可以用var或let替换const,但如果不打算修改element,最好使用const)。
析构赋值允许您从数组或对象中提取值并将它们赋给变量。在本例中,const [key, value]意味着不是将[key, value]数组赋值给element,而是将该数组的第一个元素赋值给key,将第二个元素赋值给value。它等价于:
for (const element of Object.entries(obj)) {
const key = element[0]
,value = element[1]
}
如您所见,解构使这变得简单得多。
Array.prototype.every()和Array.prototype.some()
如果指定的回调函数对数组中的每个元素都返回true,则every()方法返回true。如果指定的回调函数对某些(至少一个)元素返回true,则some()方法返回true。
Const arr = [1,2,3] // true,因为每个元素都大于0 console.log(加勒比海盗。每个(x => x > 0)) // false,因为3^2大于5 console.log(加勒比海盗。数学。Pow (x, 2) < 5)) // true,因为2是偶数(除以2的余数是0) console.log(加勒比海盗。(x => x % 2 === 0)) // false,因为所有元素都不等于5 console.log(加勒比海盗。一些(x => x == 5))
Array.prototype.find()和Array.prototype.filter()
find()方法返回满足所提供回调函数的第一个元素。filter()方法返回满足所提供回调函数的所有元素的数组。
const arr = [1, 2, 3] // 2, because 2^2 !== 2 console.log(arr.find(x => x !== Math.pow(x, 2))) // 1, because it's the first element console.log(arr.find(x => true)) // undefined, because none of the elements equals 7 console.log(arr.find(x => x === 7)) // [2, 3], because these elements are greater than 1 console.log(arr.filter(x => x > 1)) // [1, 2, 3], because the function returns true for all elements console.log(arr.filter(x => true)) // [], because none of the elements equals neither 6 nor 7 console.log(arr.filter(x => x === 6 || x === 7))
Array.prototype.map ()
map()方法返回一个数组,其中包含对数组元素调用所提供的回调函数的结果。
Const arr = [1,2,3] console.log(加勒比海盗。Map (x => x + 1)) // [2,3,4] console.log(加勒比海盗。地图(x = > String.fromCharCode (96 + x))) / / (a, b, c的) console.log(加勒比海盗。Map (x => x)) // [1,2,3] (no-op) console.log(加勒比海盗。map(x =>数学。Pow (x, 2)) // [1,4,9] console.log(arr.map(String)) // ['1', '2', '3']
Array.prototype.reduce ()
reduce()方法通过调用提供的带有两个元素的回调函数,将数组减少为单个值。
Const arr = [1,2,3] //数组元素的和 console.log(加勒比海盗。Reduce ((a, b) => a + b)) // 6 //数组中最大的数字。 console.log(加勒比海盗。Reduce ((a, b) => a > b ?A: b)) // 3
reduce()方法有一个可选的第二个参数,它是初始值。当调用reduce()的数组可以有零个或一个元素时,这很有用。例如,如果我们想创建一个函数sum(),它接受一个数组作为参数,并返回所有元素的和,我们可以这样写:
Const sum = arr => arr。Reduce ((a, b) => a + b, 0) Console.log (sum([])) // 0 Console.log (sum([4])) // 4 Console.log (sum([2,5])
以防万一,有人在2017年或以后访问这个问题,并寻找一种容易记住的方法,这里有一篇关于在JavaScript中访问嵌套对象而不被迷惑的详细博客文章
无法读取未定义错误的属性“foo”
1. Oliver Steele的嵌套对象访问模式
最简单、最干净的方法是使用Oliver Steele的嵌套对象访问模式
const name = ((user || {}).personalInfo || {}).name;
用这个符号,你永远不会碰到
无法读取未定义的属性“名称”。
你基本上检查user是否存在,如果不存在,你立即创建一个空对象。这样,下一层键将始终从一个存在的对象或空对象访问,而不会从undefined访问。
2. 使用数组缩减访问嵌套对象
为了能够访问嵌套数组,您可以编写自己的数组reduce util。
const getNestedObject = (nestedObj, pathArr) => {
return pathArr.reduce((obj, key) =>
(obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}
// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);
// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'addresses', 0, 'city']);
// this will return the city from the first address item.
还有一种出色的类型处理最小库类型可以为您完成所有这些。
你需要做的非常简单,它可以通过递归来实现:
const json_object = {
"item1":{
"name": "apple",
"value": 2,
},
"item2":{
"name": "pear",
"value": 4,
},
"item3":{
"name": "mango",
"value": 3,
"prices": {
"1": "9$",
"2": "59$",
"3": "1$"
}
}
}
function walkJson(json_object){
for(obj in json_object){
if(typeof json_object[obj] === 'string'){
console.log(`${obj}=>${json_object[obj]}`);
}else{
console.log(`${obj}=>${json_object[obj]}`);
walkJson(json_object[obj]);
}
}
}
walkJson(json_object);