Iterate through Nested JavaScript Objects

2019-01-04 11:34发布

I'm trying to iterate through a nested object to retrieve a specific object identified by a string. In the sample object below, the identifier string is the "label" property. I can't wrap my head around how to iterate down through the tree to return the appropriate object. Any help or suggestions would be greatly appreciated.

var cars = 
    {
        label: 'Autos',
        subs:
            [
                {
                    label: 'SUVs',
                    subs: []
                },
                {
                    label: 'Trucks',
                    subs: [
                              {
                                label: '2 Wheel Drive',
                                subs: []
                              },
                              {
                                label: '4 Wheel Drive',
                                subs: [
                                          {
                                            label: 'Ford',                                        
                                            subs: []
                                          },
                                          {
                                            label: 'Chevrolet',
                                            subs: []                                      
                                          }
                                      ]                          
                              }
                          ]    
                },
                {
                    label: 'Sedan',
                    subs: []
                }
            ]
    }

8条回答
The star\"
2楼-- · 2019-01-04 11:36

Here is a dead-simple method using only 3 variables without recursion.

function forEachNested(O, f){
    O = Object.values(O);
    var cur;
    while (O.length){
        cur = O.pop()
        f(cur);
        if (typeof cur === 'object' && cur.constructor === Object)
            O.push.apply(O, Object.values(cur));
    }
}

If you have a problem with circular references (e.g. having object A's values being object A itself in such as that object A contains itself), or you just need the keys then the following slower solution is available.

function forEachNested(O, f){
    O = Object.entries(O);
    var cur;
    function applyToEach(x){return cur[1][x[0]] === x[1]} 
    while (O.length){
        cur = O.pop();
        f(cur[0], cur[1]);
        if (typeof cur[1] === 'object' && cur[1].constructor === Object && 
          !O.some(applyToEach))
            O.push.apply(O, Object.entries(cur[1]));
    }
}

Since these methods does not use any recursion of any sort, these functions are well suited for areas where you might have thousands of levels of depth.

查看更多
Fickle 薄情
3楼-- · 2019-01-04 11:42

The following code assumes no circular references, and assumes subs is always an array (and not null in leaf nodes):

function find(haystack, needle) {
  if (haystack.label === needle) return haystack;
  for (var i = 0; i < haystack.subs.length; i ++) {
    var result = find(haystack.subs[i], needle);
    if (result) return result;
  }
  return null;
}
查看更多
乱世女痞
4楼-- · 2019-01-04 11:47

You can create a recursive function like this to do a depth-first traversal of the cars object.

var findObjectByLabel = function(obj, label) {
    if(obj.label === label) { return obj; }
    for(var i in obj) {
        if(obj.hasOwnProperty(i)){
            var foundLabel = findObjectByLabel(obj[i], label);
            if(foundLabel) { return foundLabel; }
        }
    }
    return null;
};

which can be called like so

findObjectByLabel(car, "Chevrolet");
查看更多
祖国的老花朵
5楼-- · 2019-01-04 11:50

The following snippet will iterate over nested objects. Objects within the objects. Feel free to change it to meet your requirements. Like if you want to add array support make if-else and make a function that loop through arrays ...

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    "p4": {
        "p4": 'value 4'
    }
};



/**
*   Printing a nested javascript object
*/
function jsonPrinter(obj) {

    for (let key in obj) {
        // checking if it's nested
        if (obj.hasOwnProperty(key) && (typeof obj[key] === "object")) {
            jsonPrinter(obj[key])
        } else {
            // printing the flat attributes
            console.log(key + " -> " + obj[key]);
        }
    }
}

jsonPrinter(p);

查看更多
爱情/是我丢掉的垃圾
6楼-- · 2019-01-04 11:52

To increase performance for further tree manipulation is good to transform tree view into line collection view, like [obj1, obj2, obj3]. You can store parent-child object relations to easy navigate to parent/child scope.

Searching element inside collection is more efficient then find element inside tree (recursion, addition dynamic function creation, closure).

查看更多
趁早两清
7楼-- · 2019-01-04 11:52

You can get through every object in the list and get which value you want. Just pass an object as first parameter in the function call and object property which you want as second parameter. Change object with your object.

const treeData = [{
        "jssType": "fieldset",
        "jssSelectLabel": "Fieldset (with legend)",
        "jssSelectGroup": "jssItem",
        "jsName": "fieldset-715",
        "jssLabel": "Legend",
        "jssIcon": "typcn typcn-folder",
        "expanded": true,
        "children": [{
                "jssType": "list-ol",
                "jssSelectLabel": "List - ol",
                "jssSelectGroup": "jssItem",
                "jsName": "list-ol-147",
                "jssLabel": "",
                "jssIcon": "dashicons dashicons-editor-ol",
                "noChildren": false,
                "expanded": true,
                "children": [{
                        "jssType": "list-li",
                        "jssSelectLabel": "List Item - li",
                        "jssSelectGroup": "jssItem",
                        "jsName": "list-li-752",
                        "jssLabel": "",
                        "jssIcon": "dashicons dashicons-editor-ul",
                        "noChildren": false,
                        "expanded": true,
                        "children": [{
                            "jssType": "text",
                            "jssSelectLabel": "Text (short text)",
                            "jssSelectGroup": "jsTag",
                            "jsName": "text-422",
                            "jssLabel": "Your Name (required)",
                            "jsRequired": true,
                            "jsTagOptions": [{
                                    "jsOption": "",
                                    "optionLabel": "Default value",
                                    "optionType": "input"
                                },
                                {
                                    "jsOption": "placeholder",
                                    "isChecked": false,
                                    "optionLabel": "Use this text as the placeholder of the field",
                                    "optionType": "checkbox"
                                },
                                {
                                    "jsOption": "akismet_author_email",
                                    "isChecked": false,
                                    "optionLabel": "Akismet - this field requires author's email address",
                                    "optionType": "checkbox"
                                }
                            ],
                            "jsValues": "",
                            "jsPlaceholder": false,
                            "jsAkismetAuthor": false,
                            "jsIdAttribute": "",
                            "jsClassAttribute": "",
                            "jssIcon": "typcn typcn-sort-alphabetically",
                            "noChildren": true
                        }]
                    },
                    {
                        "jssType": "list-li",
                        "jssSelectLabel": "List Item - li",
                        "jssSelectGroup": "jssItem",
                        "jsName": "list-li-538",
                        "jssLabel": "",
                        "jssIcon": "dashicons dashicons-editor-ul",
                        "noChildren": false,
                        "expanded": true,
                        "children": [{
                            "jssType": "email",
                            "jssSelectLabel": "Email",
                            "jssSelectGroup": "jsTag",
                            "jsName": "email-842",
                            "jssLabel": "Email Address (required)",
                            "jsRequired": true,
                            "jsTagOptions": [{
                                    "jsOption": "",
                                    "optionLabel": "Default value",
                                    "optionType": "input"
                                },
                                {
                                    "jsOption": "placeholder",
                                    "isChecked": false,
                                    "optionLabel": "Use this text as the placeholder of the field",
                                    "optionType": "checkbox"
                                },
                                {
                                    "jsOption": "akismet_author_email",
                                    "isChecked": false,
                                    "optionLabel": "Akismet - this field requires author's email address",
                                    "optionType": "checkbox"
                                }
                            ],
                            "jsValues": "",
                            "jsPlaceholder": false,
                            "jsAkismetAuthorEmail": false,
                            "jsIdAttribute": "",
                            "jsClassAttribute": "",
                            "jssIcon": "typcn typcn-mail",
                            "noChildren": true
                        }]
                    },
                    {
                        "jssType": "list-li",
                        "jssSelectLabel": "List Item - li",
                        "jssSelectGroup": "jssItem",
                        "jsName": "list-li-855",
                        "jssLabel": "",
                        "jssIcon": "dashicons dashicons-editor-ul",
                        "noChildren": false,
                        "expanded": true,
                        "children": [{
                            "jssType": "textarea",
                            "jssSelectLabel": "Textarea (long text)",
                            "jssSelectGroup": "jsTag",
                            "jsName": "textarea-217",
                            "jssLabel": "Your Message",
                            "jsRequired": false,
                            "jsTagOptions": [{
                                    "jsOption": "",
                                    "optionLabel": "Default value",
                                    "optionType": "input"
                                },
                                {
                                    "jsOption": "placeholder",
                                    "isChecked": false,
                                    "optionLabel": "Use this text as the placeholder of the field",
                                    "optionType": "checkbox"
                                }
                            ],
                            "jsValues": "",
                            "jsPlaceholder": false,
                            "jsIdAttribute": "",
                            "jsClassAttribute": "",
                            "jssIcon": "typcn typcn-document-text",
                            "noChildren": true
                        }]
                    }
                ]
            },
            {
                "jssType": "paragraph",
                "jssSelectLabel": "Paragraph - p",
                "jssSelectGroup": "jssItem",
                "jsName": "paragraph-993",
                "jssContent": "* Required",
                "jssIcon": "dashicons dashicons-editor-paragraph",
                "noChildren": true
            }
        ]
        
    },
    {
        "jssType": "submit",
        "jssSelectLabel": "Submit",
        "jssSelectGroup": "jsTag",
        "jsName": "submit-704",
        "jssLabel": "Send",
        "jsValues": "",
        "jsRequired": false,
        "jsIdAttribute": "",
        "jsClassAttribute": "",
        "jssIcon": "typcn typcn-mail",
        "noChildren": true
    },
    
];




 function findObjectByLabel(obj, label) {
       for(var elements in obj){
           if (elements === label){
                console.log(obj[elements]);
           }
            if(typeof obj[elements] === 'object'){
            findObjectByLabel(obj[elements], 'jssType');
           }
          
       }
};

 findObjectByLabel(treeData, 'jssType');

查看更多
登录 后发表回答