字符串化(转换为 JSON)具有循环引用的 JavaScript 对象

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

I've got a JavaScript object definition which contains a circular reference: it has a property that references the parent object.

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

It also has functions that I don't want to be passed through to the server. How would I serialize and deserialize these objects?

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

I've read that the best method to do this is to use Douglas Crockford's stringify. However, I'm getting the following error in Chrome:

TypeError:将循环结构转换为 JSON

TypeError: Converting circular structure to 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 等属性.

This is a test case that I created for this question. There are errors within this code but essentially I have objects within objects, and a reference passed to each object to show what the parent object is when the object is created. Each object also contains functions, which I don't want stringified. I just want the properties such as the Person.Name.

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

How do I serialize before sending to the server and deserialize it assuming that the same JSON is passed back?

推荐答案

循环结构当你有一个对象的属性直接是对象本身时会发生错误(a ->a)或间接(a -> b -> a).

Circular structure error occurs when you have a property of the object which is the object itself directly (a -> a) or indirectly (a -> b -> a).

为了避免错误消息,告诉 JSON.stringify 在遇到循环引用时该怎么做.例如,如果您有一个人指向另一个人(父母"),而该人可能(也可能不)指向原始人,请执行以下操作:

To avoid the error message, tell JSON.stringify what to do when it encounters a circular reference. For example, if you have a person pointing to another person ("parent"), which may (or may not) point to the original person, do the following:

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

stringify 的第二个参数是一个过滤函数.在这里,它只是将引用的对象转换为其 ID,但您可以自由地做任何您想做的事情来破坏循环引用.

The second parameter to stringify is a filter function. Here it simply converts the referred object to its ID, but you are free to do whatever you like to break the circular reference.

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

You can test the above code with the following:

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)中的保留字.这往往会导致混乱......

BTW, I'd choose a different attribute name to "parent" since it is a reserved word in many languages (and in DOM). This tends to cause confusion down the road...

相关文章