javascript - Javascript - 如何访问和处理嵌套对象和数组?

我有一个包含对象和数组的嵌套数据结构,如何提取信息,换句话说,怎样访问特定或多个值(或键)?

例如:

 

var data = {


 code: 42,


 items: [{


 id: 1,


 name: 'foo'


 }, {


 id: 2,


 name: 'bar'


 }]


};



我如何访问 items 中第二项的name

时间:

你可以用这种方式访问

 
data.items[1].name



 

或者

 

data[" items" ][1][" name" ]



两种方法都相等。

如果你试图通过id或name从示例结构访问一个item,如果不知道它在数组中的位置,最简单的方法是使用 underscore.js库:

 

var data = {


 code: 42,


 items: [{


 id: 1,


 name: 'foo'


 }, {


 id: 2,


 name: 'bar'


 }]


};



_.find(data.items, function(item) {


 return item.id === 2;


});


//Object {id: 2, name:" bar" }



从我的经验来看,使用高阶函数,而且不是forfor..in循环会导致更易于理解的代码,因此更加可维护。

只是我的2美分。

对象和数组有许多内置的方法,可以帮助你处理数据。

注意:在许多示例中,我使用箭头函数,它们与函数表达式相似,但是,它们在词汇上绑定了this值。

使用 Object.keys()Object.values() (2017 )和 Object.entries() crfs,

Object.keys()返回对象的键数组,.Object.values()返回对象的值数组,返回一个数组,其中包含对象的键和相应值的数组,格式为。

 

const obj = {


 a: 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]]

带有循环和destructuring赋值的Object.entries()

 

const obj = {


 a: 1


, b: 2


, c: 3


}



for (const [key, value] of Object.entries(obj)) {


 console.log(`key: ${key}, value: ${value}`)


}

在循环和 destructuring分配中迭代Object.entries()的结果是非常方便的

对于循环,可以迭代数组元素,语法是 for (const element of array) (我们可以用 varlet替换const,但是,如果不打算修改 element,最好使用 const )。

Destructuring赋值允许从数组或对象中提取值,并且将它们分配给变量,在这种情况下,const[key, value]代表不将[key, value]数组分配给element,我们将该数组的第一个元素分配给 keyvalue ,它等效于:

 

for (const element of Object.entries(obj)) {


 const key = element[0]


 , value = element[1]


}



你可以看到,destructuring使得这变得更加简单。

Array.prototype.every()Array.prototype.some()

如果指定的回调函数为数组的每个元素返回true,则 every()方法返回true ,如果指定的回调函数为某些(至少一个)元素返回true,则 some()方法返回true

 

const arr = [1, 2, 3]



//true, because every element is greater than 0


console.log(arr.every(x => x> 0))


//false, because 3^2 is greater than 5


console.log(arr.every(x => Math.pow(x, 2) <5))


//true, because 2 is even (the remainder from dividing by 2 is 0)


console.log(arr.some(x => x % 2 === 0))


//false, because none of the elements is equal to 5


console.log(arr.some(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(arr.map(x => x + 1))//[2, 3, 4]


console.log(arr.map(x => String.fromCharCode(96 + x)))//['a', 'b', 'c']


console.log(arr.map(x => x))//[1, 2, 3] (no-op)


console.log(arr.map(x => Math.pow(x, 2)))//[1, 4, 9]


console.log(arr.map(String))//['1', '2', '3']

Array.prototype.reduce()

reduce()方法通过调用提供的回调函数,将数组缩减为单个值。

 

const arr = [1, 2, 3]



//Sum of array elements.


console.log(arr.reduce((a, b) => a + b))//6


//The largest number in the array.


console.log(arr.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]))//7

这个问题相当古老,所以,作为当代的更新,随着ES2015的开始,可以选择获取你需要的数据,现在有一个叫做对象destructuring的特性来访问嵌套对象。

 

const data = {


 code: 42,


 items: [{


 id: 1,


 name: 'foo'


 }, {


 id: 2,


 name: 'bar'


 }]


};



const {


 items: [, {


 name: secondName


 }]


} = data;



console.log(secondName);

上面的例子从一个名为items的数组中创建了一个名为secondName的变量,该数组中的第一个对象表示孤独。

值得注意的是,这个例子可能有点过分,因为简单的数组访问更容易阅读,但是,它在分解对象时非常有用。

如果你愿意包含库,使用JSONPath将是最灵活的解决方案之一: https://github.com/s3u/JSONPath (节点浏览器),

对于你的用例,json路径将是:

 
$..items[1].name



 

所以:

 

var secondName = jsonPath.eval(data," $..items[1].name" );



要访问嵌套属性,你需要指定它名称,然后通过对象进行搜索。

如果你已经知道确切路径,那么就可以将它硬编码到你的脚本中,如下所示:

 

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)



路径是一种表示: 首先获取带有键items的对象,它正好是一个数组,然后使用1 -st元素(0索引数组 ),最后一个带键name的对象在这个数组元素中,它正好是字符串bar

如果你的路径很长,你甚至可以使用String.split来简化这一切-,

 

'items.1.name'.split('.').reduce((a,v) => a[v], data)



这只是普通JavaScript,不使用任何第三方库,如jQuery或lodash 。

我喜欢JQuery,它更简洁,易于阅读。

 

 $.each($.parseJSON(data), function (key, value) {


 alert(value.<propertyname>);


});

你可以使用lodash _get函数:

 

var object = { 'a': [{ 'b': { 'c': 3 } }] };



_.get(object, 'a[0].b.c');


//=> 3



如果你正在寻找一个或多个符合特定条件的对象你可以使用query-js

 

//will return all elements with an id larger than 1


data.items.where(function(e){return e.id> 1;});


//will return the first element with an id larger than 1


data.items.first(function(e){return e.id> 1;});


//will return the first element with an id larger than 1 


//or the second argument if non are found


data.items.first(function(e){return e.id> 1;},{id:-1,name:" " });



还有一个singlesingleOrDefault,它们的工作方式与 firstfirstOrDefault一样,唯一的区别是,如果找到多个匹配项,它们将抛出。

...