首页 文章

Stringify(转换为JSON)具有循环引用的JavaScript对象

提问于
浏览
55

我有一个包含循环引用的JavaScript对象定义:它有一个引用父对象的属性 .

它还具有我不想传递给服务器的功能 . 我如何序列化和反序列化这些对象?

我读过这样做的最好方法是使用Douglas Crockford的stringify . 但是,我在Chrome中收到以下错误:

TypeError:将循环结构转换为JSON

代码:

function finger(xid, xparent){
    this.id = xid;
    this.xparent;
    //other attributes
}

function arm(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.fingers = [];

    //other attributes

    this.moveArm = function() {
        //moveArm function details - not included in this testcase
        alert("moveArm Executed");
    }
}

 function person(xid, xparent, xname){
    this.id = xid;
    this.parent = xparent;
    this.name = xname
    this.arms = []

    this.createArms = function () {
        this.arms[this.arms.length] = new arm(this.id, this);
    }
}

function group(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.people = [];
    that = this;

    this.createPerson = function () {
        this.people[this.people.length] = new person(this.people.length, this, "someName");
        //other commands
    }

    this.saveGroup = function () {
        alert(JSON.stringify(that.people));
    }
}

这是我为此问题创建的测试用例 . 此代码中存在错误,但实际上我在对象中有对象,并且传递给每个对象以显示创建对象时父对象的内容 . 每个对象还包含我不想要字符串化的函数 . 我只想要 Person.Name 这样的属性 .

假设传回相同的JSON,如何在发送到服务器之前进行序列化并反序列化?

5 回答

  • 9

    如果对象的属性是对象本身( a -> a )或间接( a -> b -> a ),则会发生 Circular structure 错误 .

    要避免出现错误消息,请告诉JSON.stringify遇到循环引用时要执行的操作 . 例如,如果您有一个人指向可能(或可能不)指向原始人的另一个人(“父母”),请执行以下操作:

    JSON.stringify( that.person, function( key, value) {
      if( key == 'parent') { return value.id;}
      else {return value;}
    })
    

    stringify 的第二个参数是过滤函数 . 这里它只是简单地将引用的对象转换为它的ID,但你可以自由地做任何你喜欢的事情来打破循环引用 .

    您可以使用以下代码测试上述代码:

    function Person( params) {
      this.id = params['id'];
      this.name = params['name']; 
      this.father = null;
      this.fingers = [];
      // etc.
    }
    
    var me = new Person({ id: 1, name: 'Luke'});
    var him = new Person( { id:2, name: 'Darth Vader'});
    me.father = him; 
    JSON.stringify(me); // so far so good
    
    him.father = me; // time travel assumed :-)
    JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
    // But this should do the job:
    JSON.stringify(me, function( key, value) {
      if(key == 'father') { 
        return value.id;
      } else {
        return value;
      };
    });
    

    顺便说一句,我选择了一个不同的属性名称“ parent ”,因为它是许多语言(和DOM)中的保留字 . 这往往会引起混乱......

  • -11

    似乎dojo可以用以下形式表示JSON中的循环引用: {"id":"1","me":{"$ref":"1"}}

    这是一个例子:

    http://jsfiddle.net/dumeG/

    require(["dojox/json/ref"], function(){
        var me = {
            name:"Kris",
            father:{name:"Bill"},
            mother:{name:"Karen"}
        };
        me.father.wife = me.mother;
        var jsonMe = dojox.json.ref.toJson(me); // serialize me
        alert(jsonMe);
    });​
    

    生产环境 :

    {
       "name":"Kris",
       "father":{
         "name":"Bill",
         "wife":{
              "name":"Karen"
          }
       },
       "mother":{
         "$ref":"#father.wife"
       }
    }
    

    注意:您还可以使用 dojox.json.ref.fromJson 方法对这些循环引用的对象进行反序列化 .

    其他资源:

    How to serialize DOM node to JSON even if there are circular references?

    JSON.stringify can't represent circular references

  • 95

    我找到了两个合适的模块来处理JSON中的循环引用 .

    这些都可以满足您的需求 .

  • 2

    发生在这个线程上,因为我需要将复杂的对象记录到页面,因为在我的特定情况下无法进行远程调试 . 发现Douglas Crockford(JSON的接受者)拥有cycle.js,它将循环引用注释为字符串,以便在解析后可以重新连接它们 . 解除循环的深层副本可以安全地通过JSON.stringify . 请享用!

    https://github.com/douglascrockford/JSON-js

    cycle.js:这个文件包含两个函数,JSON.decycle和JSON.retrocycle,它们可以用JSON编码循环结构和dag,然后恢复它们 . 这是ES5不提供的功能 . JSONPath用于表示链接 .

  • 5

    我使用以下内容来消除循环引用:

    JS.dropClasses = function(o) {
    
        for (var p in o) {
            if (o[p] instanceof jQuery || o[p] instanceof HTMLElement) {
                o[p] = null;
            }    
            else if (typeof o[p] == 'object' )
                JS.dropClasses(o[p]);
        }
    };
    
    JSON.stringify(JS.dropClasses(e));
    

相关问题