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

例如:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

我如何访问项目中的第二个项目的名称?


当前回答

以防万一,有人在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.

还有一种出色的类型处理最小库类型可以为您完成所有这些。

其他回答

我不认为提问只关心一个层次的嵌套对象,所以我提出下面的演示来演示如何访问深嵌套json对象的节点。好的,让我们找到id为5的节点。

var data = { code: 42, items: [{ id: 1, name: 'aaa', items: [{ id: 3, name: 'ccc' }, { id: 4, name: 'ddd' }] }, { id: 2, name: 'bbb', items: [{ id: 5, name: 'eee' }, { id: 6, name: 'fff' }] }] }; var jsonloop = new JSONLoop(data, 'id', 'items'); jsonloop.findNodeById(data, 5, function(err, node) { if (err) { document.write(err); } else { document.write(JSON.stringify(node, null, 2)); } }); <script src="https://rawgit.com/dabeng/JSON-Loop/master/JSONLoop.js"></script>

要访问嵌套属性,需要指定其名称,然后搜索对象。

如果你已经知道确切的路径,那么你可以像这样在你的脚本中硬编码它:

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。

下划线js的方式

这是一个JavaScript库,它提供了一大堆有用的函数式编程助手,而不扩展任何内置对象。

解决方案:

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

var item = _.findWhere(data.items, {
  id: 2
});
if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}

//using find - 

var item = _.find(data.items, function(item) {
  return item.id === 2;
});

if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}
var ourStorage = {


"desk":    {
    "drawer": "stapler"
  },
"cabinet": {
    "top drawer": { 
      "folder1": "a file",
      "folder2": "secrets"
    },
    "bottom drawer": "soda"
  }
};
ourStorage.cabinet["top drawer"].folder2; // Outputs -> "secrets"

or

//parent.subParent.subsubParent["almost there"]["final property"]

基本上,在它下面展开的每个后代之间使用一个点,当你有由两个字符串组成的对象名称时,你必须使用["obj Name"]符号。否则,只要一个点就足够了;

来源:https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects

在此基础上,访问嵌套数组将如下所示:

var ourPets = [
  {
    animalType: "cat",
    names: [
      "Meowzer",
      "Fluffy",
      "Kit-Cat"
    ]
  },
  {
    animalType: "dog",
    names: [
      "Spot",
      "Bowser",
      "Frankie"
    ]
  }
];
ourPets[0].names[1]; // Outputs "Fluffy"
ourPets[1].names[0]; // Outputs "Spot"

来源: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

如果你试图通过id或名称从示例结构中访问一个项,而不知道它在数组中的位置,最简单的方法是使用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"}

根据我的经验,使用高阶函数而不是for或for..in循环会导致代码更容易推理,因此更易于维护。

这只是我的个人意见。