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

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

问题描述

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

例如:

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

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

解决方案

初步

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

(普通)对象的格式为

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

数组的格式为

[value, value, ...]

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

可以使用点符号

访问属性

const value = obj.someProperty;

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

// 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];

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

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数据类型,即数组和对象(以及如何使用它们进行了解释).问题使用JavaScript解析JSON?解释了如何解析JSON? /p>

其他阅读材料

如何访问数组和对象是JavaScript的基本知识,因此建议阅读使用对象

  • 数组
  • 出色的JavaScript-数据结构


  • 访问嵌套数据结构

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

    这里是一个例子:

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

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

    这是我们如何逐步进行:

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

    data.items
    

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

    data.items[1]
    

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

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

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

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


    我正在尝试访问属性,但只得到undefined回来?

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

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

    使用 console.log for [MDN] 循环使数组迭代所有属性/元素.

    对象

    要遍历data的所有属性,我们可以遍历对象,如下所示:

    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] .

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

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

    数组

    要遍历data.items 数组的所有元素,我们使用for循环:

    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遍历数组,但是有理由应避免这样做:.

    随着对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(ES6)的环境中,您还可以使用 可迭代 :

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

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


    如果我不知道数据结构的深度"怎么办?

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

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

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

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

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

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

    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控制台的输出):

    > 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__.后者是用于对象原型链的内部属性.但是,原型链和继承超出了此答案的范围.

    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)?

    For example:

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

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

    解决方案

    Preliminaries

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

    (Plain) Objects have the form

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

    Arrays have the form

    [value, value, ...]
    

    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".

    Properties can be accessed either using dot notation

    const value = obj.someProperty;
    

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

    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? .

    Further reading material

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



    Accessing nested data structures

    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.

    Here is an example:

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

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

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

    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]
    

    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'];
    


    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
    

    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
    


    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.

    Objects

    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
    }
    

    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].

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

    Arrays

    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`.
    }
    

    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?.

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

    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
    }
    

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


    What if the "depth" of the data structure is unknown to me?

    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.

    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.

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



    Helpers

    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 ]
    

    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
    

    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天全站免登陆