Fullk33 Fullk33 - 1 month ago 15
Javascript Question

JavaScript Iterating over object properties - Stuck in circular reference loop

I have a big object (it has around 200 properties) and I want to print it like so:

[property1: alice, property2: bob, property3: 42, ...]


If the property is a function, I want it to print the code of the function and if it is an array, I want it to print every element of that array. Also, if the property is an object it should also print it's properties and so on...

I have tried to implement this recursively but of course the call stack got too big quite quickly. Then I moved on to a iterative implementation using a stack. Here is what I've got:

function getPropertyString(obj) {
var res = "";
var stack = [];
stack.push(obj);
while(stack.length > 0){
var object = stack.pop();
res += "[";
for(var prop in object) {
if(prop == null) continue;
if(typeof object[prop] === 'object') {
stack.push(object[prop]);
} else {
res += prop + ": " +
object[prop].toString().replace(/[\t\r\n]/g, "") + ", ";
}
}
res += "],";
}
return res;
}


This works fine if you have an object like

var a = {
b : {
c : "hello",
d : "world"
},
e : "alice",
f : "bob",
g : function() {
console.log("hello");
},
h : [1, 2, 3]
}


but let's say you modify
a
so that
a.x = {}; a.x.prototype = a;
. Then my function would get stuck in an infinite loop.

How could I get around this?

Answer

Create an array of objects that has been processed from the stack, and do not process them again: (I marked the lines I added to do this)

function getPropertyString(obj) {
    var res = "";
    var stack = [];
    var objectHistory = []; // added this
    stack.push(obj);
    while(stack.length > 0){
        var object = stack.pop();
        if (objectHistory.indexOf(object) != -1) continue;  // added this
        objectHistory.push(object);  // added this
        res += "[";
        for(var prop in object) {
            if(prop == null) continue;
            if(typeof object[prop] === 'object') {
                stack.push(object[prop]);
            } else {
                res += prop + ": " +
                       object[prop].toString().replace(/[\t\r\n]/g, "") + ", ";
            }
        }
        res += "],";
    }
    return res;
}

var a = {
    b : {
        c : "hello",
        d : "world"
    },
    e : "alice",
    f : "bob",
    g : function() {
        console.log("hello");
    },
    h : [1, 2, 3]
};

a.x = {
  i: "I am X"
};
a.x.prototype = a;

console.log(getPropertyString(a));