Detecting and fixing circular references in JavaScript

后端 未结 15 834
庸人自扰
庸人自扰 2020-11-28 23:29

Given I have a circular reference in a large JavaScript object

And I try JSON.stringify(problematicObject)

And the browser throws

15条回答
  •  爱一瞬间的悲伤
    2020-11-29 00:16

    Most of the other answers only show how to detect that an object-tree has a circular-reference -- they don't tell you how to fix those circular references (ie. replacing the circular-reference values with, eg. undefined).

    The below is the function I use to replace all circular-references with undefined:

    export const specialTypeHandlers_default = [
        // Set and Map are included by default, since JSON.stringify tries (and fails) to serialize them by default
        {type: Set, keys: a=>a.keys(), get: (a, key)=>key, delete: (a, key)=>a.delete(key)},
        {type: Map, keys: a=>a.keys(), get: (a, key)=>a.get(key), delete: (a, key)=>a.set(key, undefined)},
    ];
    export function RemoveCircularLinks(node, specialTypeHandlers = specialTypeHandlers_default, nodeStack_set = new Set()) {
        nodeStack_set.add(node);
    
        const specialHandler = specialTypeHandlers.find(a=>node instanceof a.type);
        for (const key of specialHandler ? specialHandler.keys(node) : Object.keys(node)) {
            const value = specialHandler ? specialHandler.get(node, key) : node[key];
            // if the value is already part of visited-stack, delete the value (and don't tunnel into it)
            if (nodeStack_set.has(value)) {
                if (specialHandler) specialHandler.delete(node, key);
                else node[key] = undefined;
            }
            // else, tunnel into it, looking for circular-links at deeper levels
            else if (typeof value == "object" && value != null) {
                RemoveCircularLinks(value, specialTypeHandlers, nodeStack_set);
            }
        }
    
        nodeStack_set.delete(node);
    }
    

    For use with JSON.stringify specifically, simply call the function above prior to the stringification (note that it does mutate the passed-in object):

    const objTree = {normalProp: true};
    objTree.selfReference = objTree;
    RemoveCircularLinks(objTree); // without this line, the JSON.stringify call errors
    console.log(JSON.stringify(objTree));
    

提交回复
热议问题