2

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

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

4

2 回答 2

1

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

文档

如果要字符串化的对象具有名为 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;
    }
}
于 2012-08-28T03:11:47.007 回答
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)
于 2012-08-28T02:42:10.660 回答