简体   繁体   中英

Recursively pass through Json to get all values for a specific key

I have a json object which looks like this:

var testJ = {"ROOT":{
        dir : 'app',
        files : [
            'index.html',
            {
                dir : 'php',
                files: [
                    'a.php',
                    {
                        dir : 'extras',
                        files : [
                            'a.js',
                            'b.js'
                        ]
                    }
                ]
            }
        ]
    }};

I need to extract all the files and append into an array (index.html,a.php,a.js..etc)

For this I wrote a javascript code as follows:

var arr=[];
    function scan(obj,append)
    {
        var k;
        if (obj instanceof Object) {
            for (k in obj){
                if (obj.hasOwnProperty(k)){
                    if(k=='files')
                    {
                      scan( obj[k],1 );  
                    }


                }                
        }
    } else {
        body += 'found value : ' + obj + '<br/>';
        if(append == 1)
        arr.push(obj);

        alert("Arr"+ arr);
    };

};

scan(testJ,0);

I am not able to figure out where am I going wrong. Could some give me pointers?

var res = [];
function gather(j) {
  for (var k in j) {
    if (k === 'files') {
      addFiles(j[k]);
    } else if (typeof j[k] === 'object') {
      gather(j[k]);
    }
  }
}
function addFiles(f) {
  for (var i = 0; i < f.length; i++) {
    if (typeof f[i] === "string") {
      body += 'found value : ' + obj + '<br/>';
      res.push(f[i]);
    } else {
      gather(f[i]);
    }
  }
}
gather(testJ);

Free tips:

instanceof is some cancerous stuff. Why does instanceof return false for some literals?

Always, always use === for comparison, not ==

I also wouldn't blindly use hasOwnProperty unless you're afraid the thing you're operating on might have a modified prototype, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in just for simplicity.

How about a map reduce approach?:

function mapJ(subject) {
  return subject.files.map(function(item) {
    if (typeof item === "string") {
      return item;
    } else {
      return parseJ(item);
    }
  });
}

function reduceJ(subject) {
  return subject.reduce(function(prev, cur) {
    return prev.concat(cur);
  }, []);
}

function parseJ(subject) {
  return reduceJ(mapJ(subject));
}

var result = parseJ(testJ));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM