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

例如︰

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

无法访问items的第二项name的方式?

2012-08-12 13:02:12
问题评论:

至少不应该谈论"JSON"如果您现在不讨论有关 JSON 交换格式。这是只是文本表示法中的一个对象。

@Marcel︰ 它必须读作"我有一个数据嵌套的数据结构JSON,如何访问特定值吗?"。知道区别,但很多人不和可能搜索"JSON"而不"对象"。很多问题实际上是窗体的"如何可以访问此 json 格式的 X"。我在我的答案中提到 JSON 的唯一的地方是我解释它是什么。如果您有建议如何进行通信这一种更好的方式,我所有的耳。

可能的重复项的JSON 在 JavaScript 中查找

@Felix Kling:i 阅读.它太有效 fr 我。非常非常感谢大家

回答:

预备知识

JavaScript 有只有一个数据类型,它可以包含多个值︰对象数组是对象的一种特殊形式。

(纯)对象具有窗体

{key: value, key: value, ...}

阵列具有窗体

[value, value, ...]

数组和对象公开key -> value的结构。而任意字符串可以用作键的对象,则必须为数字,数组中的键。也称为"属性"键-值对。.

可以访问属性,可以使用点表示法

var value = obj.someProperty;

括号表示法,如果属性名称不会有效 JavaScript 中标识符名称[技术]或名称的变量的值︰

// the space is not a valid character in identifier names
var value = obj["some Property"];

// property name as variable
var name = "some Property";
var value = obj[name];

因此,数组元素只能访问使用括号表示法︰

var value = arr[5]; // arr.5 would be a syntax error

// property name / index as variable
var x = 5;
var value = arr[x];

稍候...JSON 呢?

JSON 是文本表示的数据,就像 XML、 YAML,CSV,和其他人一样。若要使用此类数据,它必须先转换为 JavaScript 数据类型,即数组和对象 (和如何处理那些已就所述)。如何分析 JSON 问题中所述JavaScript 解析 json 格式? .

进一步阅读材料

如何访问数组和对象是基本的 JavaScript 知识,因此最好阅读MDN JavaScript 指南,尤其是部分



嵌套的数据结构的访问

嵌套的数据结构是数组或对象,它是指其他数组或对象,即其值是数组或对象。这样的结构可以通过连续应用点或括号表示法来访问。

下面是一个示例︰

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

让我们假设我们想要访问的第二项的name

下面是我们如何做它逐步︰

我们可以看到data是对象,因此可以访问其属性使用点表示法。访问items属性,如下所示︰

data.items

值为一个数组,以访问其第二个元素,我们必须使用括号表示法︰

data.items[1]

此值是一个对象,我们使用点表示法再次访问name属性。所以我们最终得到的︰

var item_name = data.items[1].name;

或者,我们也可以使用括号表示法有关的任何属性,尤其是名称包含的字符应所做点表示法用法无效︰

var item_name = data['items'][1]['name'];

我正在尝试访问的属性,但是却回只undefined

多数情况下当您正在获取undefined对象数组只是没有具有该名称的属性。

var foo = {bar: {baz: 42}};
console.log(foo.baz); // undefined

使用console.logconsole.dir和检查对象的结构/阵列。您尝试访问的属性可能会在嵌套的对象上实际定义 / 阵列。

console.log(foo.bar.baz); // 42

如果属性名称是动态的我不知道他们事先吗?

如果属性名称是未知的或者我们想要访问一个对象的所有属性 / 元素的数组,我们可以使用for...in [MDN]循环对象和for [MDN]循环来循环访问所有属性的阵列 / 元素。

对象

若要循环访问的data的所有属性,我们可以循环访问对象如下所示︰

for(var prop in data) {
    // `prop` contains the name of each property, i.e. `'code'` or `'items'`
    // consequently, `data[prop]` refers to the value of each property, i.e.
    // either `42` or the array
}

根据对象来自 (和您希望如何),可能需要测试每个迭代中,是否该属性实际上是对象的属性,或者它是一个继承的属性。你可以使用Object#hasOwnProperty [MDN] .

作为替代for...in hasOwnProperty,您可以使用Object.keys [MDN]要获取的属性名称的数组:

Object.keys(data).forEach(function(prop) {
  // `prop` is the property name
  // `data[prop]` is the property value
});

数组

要循环访问data.items 数组的所有元素,我们使用一个for循环︰

for(var i = 0, l = data.items.length; i < l; i++) {
    // `i` will take on the values `0`, `1`, `2`,..., i.e. in each iteration
    // we can access the next element in the array with `data.items[i]`, example:
    // 
    // var obj = data.items[i];
    // 
    // Since each element is an object (in our example),
    // we can now access the objects properties with `obj.id` and `obj.name`. 
    // We could also use `data.items[i].id`.
}

此外可以使用for...in来循环访问数组,但有的原因为什么应该避免这︰为什么 (var 列表中的项) 是与阵列视为在 JavaScript 中的不良习惯?.

使用 ECMAScript 5 增加浏览器支持,阵列方法forEach [MDN]变的有趣的替代︰

data.items.forEach(function(value, index, array) {
    // The callback is executed for each element in the array.
    // `value` is the element itself (equivalent to `array[index]`)
    // `index` will be the index of the element in the array
    // `array` is a reference to the array itself (i.e. `data.items` in this case)
}); 

在环境中支持 ES2015 (ES5),也可以使用for...of [MDN]循环,不仅工作对于数组,但对于任何iterable :

for (var item of data.items) {
   // `item` is the array element, **not** the index
}

在每个迭代中,for...of直接让我们的下一个元素的 iterable 没有"索引"来访问或使用。


如果数据结构的"深度"不知道给我吗?

"深度"的数据结构 (即多少每个嵌套的对象数组) 除了未知的密钥,它有,也是未知的可能。如何访问深层嵌套的属性取决于确切的数据结构,然后?

如果该数据结构包含重复的结构,如二进制树的表示形式的解决方案通常包括以递归方式 [维基百科]访问数据结构的每个级别。

下面是一个示例获取第一个二进制树的叶节点︰

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 be a leaf node
        return node;
    }
}

var first_leaf = getLeaf(root);

var 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 be a leaf node
        return node;
    }
}

alert(getLeaf(root).data);

一种更具一般性访问未知的键和深度嵌套的数据结构方法是值的测试的类型,并采取相应的措施。

下面是一个示例将嵌套的数据结构中的所有基元值添加到数组中 (假设它不包含任何函数)。如果我们遇到一个对象 (或数组) 只需调用toArray再次对该值 (递归调用)。

function toArray(obj) {
    var result = [];
    for (var prop in obj) {
        var value = obj[prop];
        if (typeof value === 'object') {
            result.push(toArray(value)); // <- recursive call
        }
        else {
            result.push(value);
        }
    }
    return result;
}

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


function toArray(obj) {
  var result = [];
  for (var prop in obj) {
    var value = obj[prop];
    if (typeof value === 'object') {
      result.push(toArray(value));
    } else {
      result.push(value);
    }
  }
  return result;
}

alert(JSON.stringify(toArray(data)));



帮助程序

由于复杂对象或数组的结构不一定很明显,我们可以在决定如何进一步移动每个步骤的值进行检查。 console.log [MDN]console.dir [MDN]帮助我们这样做。例如 (铬控制台的输出)︰

> console.log(data.items)
 [ Object, Object ]

这里我们可以看到, data.items是包含这两个对象的两个元素的数组。在 Chrome 控制台对象可以甚至展开和立即检查。

> console.log(data.items[1])
  Object
     id: 2
     name: "bar"
     __proto__: Object

这告诉我们, data.items[1]是一个对象,然后展开它后,我们发现它具有三个属性、 idname__proto__后者是用于对象的原型链的内部属性。原型链和继承位于作用域之外对此回答,不过。

一些正在此处链接什么要求如何执行此操作在 jQuery,要公平地简化了 1 或 2 事物。不确定是否进行这多个 megapost 或回答那些单独的基础知识介绍什么是对象上什么是数组通常是真的...要求。

您可以访问它通过这种方式

data.items[1].name

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

这两种方式都是相同的。

这帮助我与我的案例更多。

是的但不是能执行数据"项目".1.name

简单但有效。

如果您正试图访问某一item从示例结构按idname,而不必知道它的位置在数组中,若要执行此操作的最简单方法是使用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 美分。

有时,访问一个嵌套的对象,该对象使用的字符串可以是理想。简单的做法是第一级例如

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 Demo

WTH 想要使用obj["arr[0].name"] ,而不是obj.arr[0].name您几乎不需要/想要处理除 serialisation 之外的单一化的对象

@Bergi-通常情况下,看到这个问题,这规范化使用,因为已发布该版本的答案。如果避免快得多使用 obj.arr[0].name,但有时人们想要传递字符串访问器周围,这是执行该操作的一个示例。

Urgh。尽管如此,几乎要平面化完整的对象只是为了使用单个字符串路径的原因,可以简单地分析,并执行动态查找。

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

供您使用情况的 json 路径是︰

$..items[1].name

因此︰

var secondName = jsonPath.eval(data, "$..items[1].name");
请输入您的翻译

Access / process (nested) objects, arrays or JSON

确认取消