使用JSON序列化图形理论树的解决方法?

时间:2012-08-27 23:56:06

标签: javascript json

我有一组节点。 每个节点都有一个子数组和一个指向其父节点的指针。 我想使用JSON.stringify对其进行序列化,但是使用父指针我显然最终会得到循环引用,而JSON会抛出异常。我可以做些什么来解决循环引用和使用JSON序列化?

相关问题:Chrome sendrequest error: TypeError: Converting circular structure to JSON

2 个答案:

答案 0 :(得分:1)

尝试一下 - 使用信息和演示数据是按钮:

// class
var Decircularizer = function() {};
// class contents
Decircularizer.prototype = {
    curId: 0x01,
    idField: '{`id´}',
    _getNewId: function() {
        return this.curId++;
    },
    _getVisited: function(obj) {
        return obj[''+this.idField];
    },
    _setVisited: function(obj) {
        return (obj[''+this.idField] = this._getNewId());
    },
    _removeVisited: function(obj){
        delete obj['' + this.idField];
    },
    decycle: function(obj, depth) {
        var $this = this;
        depth = depth || 0;
        var key = this._getVisited(obj);
        if (key > 0x00) return this.idField + key;

        if(!jQuery.isPlainObject(obj))
            return obj;

        key = this._setVisited(obj);
        jQuery.each(obj, function(prop, val){
            if (prop == $this.idField) return;
            if (jQuery.isFunction(obj[prop])) delete obj[prop];
            else obj[prop] = $this.decycle(val, depth + 1);
        });
        return obj;
    },
    recycle: function(obj){
        var $this = this;
        var ids = {};
        this._searchIds(obj, ids);
        return this._recycle(obj, ids);
    },
    _recycle: function(obj, ids){
        var $this = this;
        if(!jQuery.isPlainObject(obj))
            return obj;
        jQuery.each(obj, function(prop, val){
            var xval = ids[val];
            if(xval)
                obj[prop] = xval;
            else
                obj[prop] = $this._recycle(val, ids);
        });
        return obj;
    },
    _searchIds: function(obj, ids){
        var $this = this
        var ids = ids || {};
        var key = this._getVisited(obj);

        if(key > 0x00) {
            ids[this.idField + key] = obj;
            $this._removeVisited(obj);
        }

        if(!jQuery.isPlainObject(obj))
            return ids;

        jQuery.each(obj, function(prop, val){
            $this._searchIds(val, ids);
        });
        return ids;
    }
};

// EXAMPLE DATA
var a = {};
var a2 = {}
a.b = a;
a.c = "hallo";
a.e = 123;
a.f = a2;
a2.x = a;

// USAGE
// new class
var ser = new Decircularizer();

// uncycle
var cleanObjectWithOutCirculars = ser.decycle(a);
console.debug(cleanObjectWithOutCirculars);


/* object looks like
Object {c: "hallo", e: 123, b: "{`id´}1", {`id´}: 1, f: Object}
    b: "{`id´}1"
    c: "hallo"
    e: 123
    f: Object
        x: "{`id´}1"
        {`id´}: 2
        __proto__: Object
    {`id´}: 1
    __proto__: Object 
*/

// recycle 
var aNew = ser.recycle(cleanObjectWithOutCirculars);
console.debug(aNew)

/*
Object {c: "hallo", e: 123, b: Object, f: Object}
    b: Object
        b: Object
        c: "hallo"
        e: 123
    f: Object
        x: Object
        __proto__: Object
    __proto__: Object
    c: "hallo"
    e: 123
    f: Object
        x: Object
            b: Object
            c: "hallo"
            e: 123
            f: Object
            __proto__: Object
        __proto__: Object
    __proto__: Object
*/

// correct (Y)

答案 1 :(得分:1)

您应该在具有父级的对象中创建自定义的toJson函数。

来自documentation

  

如果要进行字符串化的对象具有名为toJSON的属性,其值为   是一个函数,然后toJSON方法自定义JSON字符串化   行为

var x = {
  foo: 'foo',
  toJSON: function () {
    return 'bar';
  }
};
var json = JSON.stringify({x: x});

所以你可以在具有父引用的对象中创建该函数,这可能是这样的吗?

MyObj = function(){
    this.xxx = 'foobar';
    this.zzz = 'foooobar';
    this.name = 'foo';
    this.parent = ...;
    toJSON = function(){
        tmp = '{'
        for(prop in MyObj){
            if(prop == 'parent'){
                tmp += 'parent: "'+ this['parent'].name +'"'; //maybe?? optional!
            }else{
                tmp += prop + ':' + this[prop].stringify + ','; //you will still use the browser function
            }
            tmp += '}            
        }
        return tmp;
    }
}