如何在JavaScript或Node.js中为JSON序列化创建安全对象

时间:2012-11-27 22:49:52

标签: javascript node.js recursion json

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

2 个答案:

答案 0 :(得分:0)

我在回答下面的问题,因为提出一个有效的解决方案有点困难。这是我发现的一些解决方案的组合,似乎运作良好。

/* 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;

    }

}());

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

答案 1 :(得分:0)

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