1

我的愿望是将给定对象编码为 JSON 的“安全”方式。这是用于记录 Node.js 中的任何抽象对象,但也可以应用于其他需求。我的研究将我指向 Node 中的 util.inspect,但这不是有效的 JSON,我希望拥有有效的 JSON,以便我以后可以重新补充水分。因为某些 Error 实例可能存在递归问题,所以我需要限制响应。此外,在某些情况下,对对象的前向和后向引用也可能是一个问题,所以我想避免重复的条目。

4

2 回答 2

0

新答案

今天,如果有人在看这个,我会使用fclone,它在这一点上比我原来的要彻底得多。


原答案:

我在下面回答我自己的问题,因为想出一个可行的解决方案有点困难。这是我找到的一些解决方案的组合,并且似乎效果很好。

/* lib/clone-safe.js
*  provides a method for creating a clone of an object without redundant object references, and protected from recursion.
*  The cloned value *should* always be safe for JSON.stringify(cloneSafe(myobj))
**/
(function(){
    var undef; //intentionally undefined value
    function cloneSafe(obj,depth){
        var refs = []; //reference to cloned objects
        depth = +depth > 0 && +depth || 6; //max recursion level

        var layerNumber = 0; //current layer being checked
        var ret = clone(obj); //start cloning

        //cleanup reference checks
        while(refs.length) {
            delete (refs.shift()).___copied;
        }

        //return the result
        return ret;

        //recursive clone method
        function clone(obj) {
            if (typeof obj == "function") return undef; //no function replication

            // Handle the 3 simple types, and null or undefined
            if (null == obj || "object" != typeof obj) return obj;

            // Handle Date
            if (obj instanceof Date) {
                var copy = new Date();
                copy.setTime(obj.getTime());
                return copy;
            }

            // Handle Array
            if (obj instanceof Array) {
                var copy = [];
                for (var i = 0, len = obj.length; i < len; i++) {
                    copy[i] = clone(obj[i]);
                }
                return copy;
            }

            // Handle Object
            if (obj instanceof Object) {
                //max recursion reached
                if (++layerNumber >= depth) {
                    layerNumber--;
                    return undef;
                }

                //handle circular and duplicate references
                if (obj.___copied) return undef; //already included
                obj.___copied = true;
                refs.push(obj);

                var copy = {};

                //export prototype
                var m = obj.constructor && obj.constructor.toString().match(/function\s+([^\(]+)/);
                if (m && m[1]) copy._prototype = m[1];

                //get expected properties from any error
                if (obj instanceof Error) {
                    copy.message = obj.message || "Error";
                    if (obj.stack) copy.stack = obj.stack;
                    if (obj.number) copy.number = obj.number;
                    if (obj.description) copy.description = obj.description;
                    if (obj.name) copy.name = obj.name;
                }

                for (var attr in obj) {
                    if (attr == "___copied") continue;
                    if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
                }
                if (obj.prototype) {
                    for (var attr in obj.prototype) {
                        if (obj.prototype.hasOwnProperty(attr) && typeof obj.prototype[attr] !== 'function') copy[attr] = clone(obj.prototype[attr]);
                        delete obj.prototype[attr].___copied; //allow prototypes to be re-scanned
                    }
                }
                layerNumber--;
                return copy;
            }

            //throw new Error("Unable to copy obj! Its type isn't supported.");
            console.log("Unable to copy obj! Unsupported type: %s", typeof obj);
            return undef; //unable to clone the object in question
        }
    }

    // AMD / RequireJS
    if (typeof define === "function" && define.amd) {
        define("clone-safe",[],function(){ return cloneSafe; });
    }
    // Node.js / CommonJS
    else if (typeof module !== "undefined" && module.exports) {
        module.exports = cloneSafe;
    }
    // browser/script include
    else {

        //provide a method for reverting global binding
        var root = this; //global on the server, window in the browser.
        var previousCloneSafe = root.cloneSafe; //backreference
        cloneSafe.noConflict = function(){
            root.cloneSafe = previousCloneSafe;
            return cloneSafe;
        };

        //bind to the global object
        root.cloneSafe = cloneSafe;

    }

}());

有一些额外的逻辑用于处理错误的对象,并确保从所述错误和给定对象的原型中获取必要的数据。响应中明确忽略了函数。当递归太深时,它将返回给定对象的未定义。

于 2012-11-27T22:49:51.990 回答
0

有一个本机 javascript JSON 对象,带有一个 stringify 方法,我认为这是你需要的:http ://www.javascripture.com/JSON#stringify

于 2012-11-29T14:24:18.490 回答