fivedoor fivedoor - 4 months ago 7
JSON Question

Checking for an object vs an array when iterating over json object

If an array is a type of object then why does the following recursive function fail to output the nested array?

The expected output and actual output are below to illustrate.

// dummy encode function
function encode(value) {
return value + " (this value was encoded!)"
}

var arr = { "title1": {
"item1": "one",
"item2": "two" },
"title2": "three",
"title3": "four",
"title4": {
"item1": [
{"arrayItem": "First array item"},
{"arrayItem": "Second array item"}
]},
"title5": {
"item1": {
"subItem1": "five",
"subItem2": "six" }
}
};

function encodeValues(arr) {
var keys = Object.keys(arr);
for (var i = 0; i < keys.length; i++) {
if (!!arr[keys[i]] && typeof arr[keys[i]] === "object") encodeValues(arr[keys[i]]);

else arr[keys[i]] = encode(arr[keys[i]]);
}
return arr;
}

var encodedValues = encodeValues(arr);

console.log(encodedValues)


Expected output:

{ title1:
{ item1: 'one (this value was encoded!)',
item2: 'two (this value was encoded!)' },
title2: 'three (this value was encoded!)',
title3: 'four (this value was encoded!)',
title4: {
item1: [
{arrayItem: First array item (this value was encoded!)},
{arrayItem: Second array item (this value was encoded!)}
]},
title5:
{ item1:
{ subItem1: 'five (this value was encoded!)',
subItem2: 'six (this value was encoded!)' } } }


Actual output:

{ title1:
{ item1: 'one (this value was encoded!)',
item2: 'two (this value was encoded!)' },
title2: 'three (this value was encoded!)',
title3: 'four (this value was encoded!)',
title4: { item1: [ [Object], [Object] ] },
title5:
{ item1:
{ subItem1: 'five (this value was encoded!)',
subItem2: 'six (this value was encoded!)' } } }


Would the solution be anything along the lines of the following i.e. check for instance of an array in the if statement?:

if (!!arr[keys[i]] && arr[keys[i]] instanceof Array) encodeValues(arr[keys[i]]);
else if (!!arr[keys[i]] && typeof arr[keys[i]] === "object") encodeValues(arr[keys[i]]);
else arr[keys[i]] = encode(arr[keys[i]]);


thanks

Answer

I think your code is doing exactly what you want, but you simply weren't logging in the format you expected.

Try console.log(JSON.stringify(encodedValues, null, 2)); so you can see inside the nested objects.

Full code (fixed up quite a bit of indentation), including the output:

// dummy encode function
function encode(value) {
  return value + " (this value was encoded!)"
}

var arr = {
  "title1": {
    "item1": "one",
    "item2": "two"
  }, 
  "title2": "three",
  "title3": "four",
  "title4": {
    "item1": [
      {
        "arrayItem": "First array item"
      },
      {
        "arrayItem": "Second array item"
      }
    ]
  },
  "title5": {
    "item1": {
      "subItem1": "five",
      "subItem2": "six"
    }
  }
};

function encodeValues(arr) {
  var keys = Object.keys(arr);
  for (var i = 0; i < keys.length; i++) {
    if (!!arr[keys[i]] && typeof arr[keys[i]] === "object") {
      encodeValues(arr[keys[i]]);
    } else {
      arr[keys[i]] = encode(arr[keys[i]]);
    }
  }
  return arr;
}

var encodedValues = encodeValues(arr);

console.log(JSON.stringify(encodedValues, null, 2));

// Output:
// {
//   "title1": {
//     "item1": "one (this value was encoded!)",
//     "item2": "two (this value was encoded!)"
//   },
//   "title2": "three (this value was encoded!)",
//   "title3": "four (this value was encoded!)",
//   "title4": {
//     "item1": [
//       {
//         "arrayItem": "First array item (this value was encoded!)"
//       },
//       {
//         "arrayItem": "Second array item (this value was encoded!)"
//       }
//     ]
//   },
//   "title5": {
//     "item1": {
//       "subItem1": "five (this value was encoded!)",
//       "subItem2": "six (this value was encoded!)"
//     }
//   }
// }