Search code examples
javascriptobjectjavascript-objects

Why doesn't circular referencing in objects use infinite memory?


I was creating a deep cloning object prototype

Object.prototype.clone = function() {
    const clonedObject = {};
    for (objectKeys in this) {
            if (typeof this[objectKeys] !== "object") {
                if (objectKeys === "clone") {
                    continue;
                }
                clonedObject[objectKeys] = this[objectKeys];
            } else {
                if (!hasCircularDependency) {
                    clonedObject[objectKeys] = this[objectKeys].clone();
                } else {
                    throw RangeError("Attempting to clone this object results in the Maximium call stack size");
                }
            }
    }
    return clonedObject;
};

function hasCircularDependency(obj) {
    try {
        JSON.stringify(obj);
    } catch(e) {
        return true;
    }
    return false;
}

and I tried cloning the window object, but I was confronted by a maximum call stack error due to circular referencing.

so I was wondering, why doesn't circular referencing use infinite memory?

after all, memory must store a reference of the parent object, then store a reference of the child object, which stores a reference of the parent object. This goes on to infinity and natively, one would think that this is true. so how does javascript handle references of circular referencing?


Solution

  • Careful with the concept of references. Because there is an infinite, walkable chain, does not mean there are infinite objects.

    Let's take a simple circular dependency. Three objects (A, B, C) each one referring to the next one in the chain, like so:

    enter image description here

    In memory, this actually looks like the following:

    • Object A, links to object C
    • Object C, links to object B
    • Object B, links to object A

    Each object effectively has itself, and a pointer to the next in the chain.

    It is only when you walk this cycle that you end up consuming infinite memory, unless you keep track of where you have already been.

    There are algorithms to detect and (sometimes, if possible) break such cycles. They're used a lot when dealing with dependency management problems. Tarjan's algorithm is one of them.