如何访问和处理嵌套对象、数组或 JSON? [英] How can I access and process nested objects, arrays or JSON?

查看:19
本文介绍了如何访问和处理嵌套对象、数组或 JSON?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a nested data structure containing objects and arrays. How can I extract the information, i.e. access a specific or multiple values (or keys)?

例如:

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

如何访问items中第二个项目的name?

How could I access the name of the second item in items?

推荐答案

Preliminaries

JavaScript 只有一种可以包含多个值的数据类型:Object.数组是一种特殊形式的对象.

Preliminaries

JavaScript has only one data type which can contain multiple values: Object. An Array is a special form of object.

(Plain) 对象具有形式

(Plain) Objects have the form

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

数组的形式

[value, value, ...]

数组和对象都暴露了一个 key ->值结构.数组中的键必须是数字,而任何字符串都可以用作对象中的键.键值对也称为属性".

Both arrays and objects expose a key -> value structure. Keys in an array must be numeric, whereas any string can be used as key in objects. The key-value pairs are also called the "properties".

可以使用点符号

const value = obj.someProperty;

括号表示法,如果属性名称不是有效的 JavaScript 标识符名称​​[spec],或者名称是一个变量的值:

or bracket notation, if the property name would not be a valid JavaScript identifier name [spec], or the name is the value of a variable:

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

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

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

For that reason, array elements can only be accessed using bracket notation:

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

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

等等……JSON 怎么样?

JSON 是数据的文本表示,就像 XML、YAML、CSV 等一样.要处理此类数据,首先必须将其转换为 JavaScript 数据类型,即数组和对象(以及如何处理这些数据刚刚解释过).问题 Parse JSON in JavaScript? 中解释了如何解析 JSON.

Wait... what about JSON?

JSON is a textual representation of data, just like XML, YAML, CSV, and others. To work with such data, it first has to be converted to JavaScript data types, i.e. arrays and objects (and how to work with those was just explained). How to parse JSON is explained in the question Parse JSON in JavaScript? .

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

How to access arrays and objects is fundamental JavaScript knowledge and therefore it is advisable to read the MDN JavaScript Guide, especially the sections

嵌套数据结构是一个数组或对象,它引用其他数组或对象,即它的值是数组或对象.可以通过连续应用点或括号表示法来访问此类结构.

A nested data structure is an array or object which refers to other arrays or objects, i.e. its values are arrays or objects. Such structures can be accessed by consecutively applying dot or bracket notation.

这是一个例子:

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

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

Let's assume we want to access the name of the second item.

以下是我们如何逐步做到这一点:

Here is how we can do it step-by-step:

正如我们看到的 data 是一个对象,因此我们可以使用点表示法访问它的属性.items 属性的访问方式如下:

As we can see data is an object, hence we can access its properties using dot notation. The items property is accessed as follows:

data.items

值是一个数组,要访问它的第二个元素,我们必须使用括号表示法:

The value is an array, to access its second element, we have to use bracket notation:

data.items[1]

这个值是一个对象,我们再次使用点表示法来访问 name 属性.所以我们最终得到:

This value is an object and we use dot notation again to access the name property. So we eventually get:

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

或者,我们可以对任何属性使用括号表示法,特别是如果名称包含会使点表示法使用无效的字符时:

Alternatively, we could have used bracket notation for any of the properties, especially if the name contained characters that would have made it invalid for dot notation usage:

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

<小时>

我试图访问一个属性,但我只得到 undefined 返回?

大多数情况下,当您获得 undefined 时,对象/数组根本没有具有该名称的属性.


I'm trying to access a property but I get only undefined back?

Most of the time when you are getting undefined, the object/array simply doesn't have a property with that name.

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

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

Use console.log or console.dir and inspect the structure of object / array. The property you are trying to access might be actually defined on a nested object / array.

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

<小时>

如果属性名称是动态的而我事先不知道怎么办?

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


What if the property names are dynamic and I don't know them beforehand?

If the property names are unknown or we want to access all properties of an object / elements of an array, we can use the for...in [MDN] loop for objects and the for [MDN] loop for arrays to iterate over all properties / elements.

对象

要迭代data的所有属性,我们可以像这样迭代对象:

To iterate over all properties of data, we can iterate over the object like so:

for (const 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].

Depending on where the object comes from (and what you want to do), you might have to test in each iteration whether the property is really a property of the object, or it is an inherited property. You can do this with Object#hasOwnProperty [MDN].

作为带有 hasOwnPropertyfor...in 的替代方案,您可以使用 Object.keys [MDN] 获取属性名称数组:

As alternative to for...in with hasOwnProperty, you can use Object.keys [MDN] to get an array of property names:

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

数组

为了遍历 data.items array 的所有元素,我们使用了 for 循环:

To iterate over all elements of the data.items array, we use a for loop:

for(let 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 来迭代数组,但有一些原因可以避免这种情况:为什么在 JavaScript 中使用数组的for(var item in list)"被认为是不好的做法?.

One could also use for...in to iterate over arrays, but there are reasons why this should be avoided: Why is 'for(var item in list)' with arrays considered bad practice in JavaScript?.

随着浏览器对 ECMAScript 5 的支持越来越多,数组方法 forEach [MDN] 也成为一个有趣的选择:

With the increasing browser support of ECMAScript 5, the array method forEach [MDN] becomes an interesting alternative as well:

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 (ES6) 的环境中,您还可以使用 for...of [MDN] 循环,其中不仅适用于数组,而且适用于任何 iterable:

In environments supporting ES2015 (ES6), you can also use the for...of [MDN] loop, which not only works for arrays, but for any iterable:

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

在每次迭代中,for...of 直接给我们迭代的下一个元素,没有索引"可以访问或使用.

In each iteration, for...of directly gives us the next element of the iterable, there is no "index" to access or use.

除了未知的键之外,数据结构的深度"(即有多少嵌套对象)也可能是未知的.如何访问深度嵌套的属性通常取决于确切的数据结构.

In addition to unknown keys, the "depth" of the data structure (i.e. how many nested objects) it has, might be unknown as well. How to access deeply nested properties usually depends on the exact data structure.

但是如果数据结构包含重复模式,例如二叉树的表示,解决方案通常包括递归 [Wikipedia] 访问数据结构的每一层.

But if the data structure contains repeating patterns, e.g. the representation of a binary tree, the solution typically includes to recursively [Wikipedia] access each level of the data structure.

这是一个获取二叉树第一个叶节点的例子:

Here is an example to get the first leaf node of a binary tree:

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;
    }
}

const first_leaf = getLeaf(root);

const 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;
    }
}

console.log(getLeaf(root).data);

访问具有未知键和深度的嵌套数据结构的一种更通用的方法是测试值的类型并采取相应的行动.

A more generic way to access a nested data structure with unknown keys and depth is to test the type of the value and act accordingly.

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

Here is an example which adds all primitive values inside a nested data structure into an array (assuming it does not contain any functions). If we encounter an object (or array) we simply call toArray again on that value (recursive call).

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

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


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

console.log(toArray(data));

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

Since the structure of a complex object or array is not necessarily obvious, we can inspect the value at each step to decide how to move further. console.log [MDN] and console.dir [MDN] help us doing this. For example (output of the Chrome console):

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

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

Here we see that that data.items is an array with two elements which are both objects. In Chrome console the objects can even be expanded and inspected immediately.

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

这告诉我们data.items[1]是一个对象,展开之后我们看到它有三个属性,idname__proto__.后者是用于对象原型链的内部属性.不过,原型链和继承超出了这个答案的范围.

This tells us that data.items[1] is an object, and after expanding it we see that it has three properties, id, name and __proto__. The latter is an internal property used for the prototype chain of the object. The prototype chain and inheritance is out of scope for this answer, though.

这篇关于如何访问和处理嵌套对象、数组或 JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆