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

use*_*500 68 javascript jquery json stringify

我有一个包含循环引用的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));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

toc*_*ker 107

如果对象的属性是直接(a -> a)或间接(a -> b -> a)(对象本身),则会发生循环结构错误.

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

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

第二个参数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;
  };
});
Run Code Online (Sandbox Code Playgroud)

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


Bra*_*one 10

似乎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);
});?
Run Code Online (Sandbox Code Playgroud)

生产:

{
   "name":"Kris",
   "father":{
     "name":"Bill",
     "wife":{
          "name":"Karen"
      }
   },
   "mother":{
     "$ref":"#father.wife"
   }
}
Run Code Online (Sandbox Code Playgroud)

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

其他资源:

如果有循环引用,如何将DOM节点序列化为JSON?

JSON.stringify不能表示循环引用


Kam*_*ski 6

无库

下面使用代用品,以产生与JSON字符串的引用(类似于JSON路径)复制/圆形的被引用对象

let s = JSON.stringify(obj, refReplacer());
Run Code Online (Sandbox Code Playgroud)

let s = JSON.stringify(obj, refReplacer());
Run Code Online (Sandbox Code Playgroud)

并遵循解析器函数从这样的“ref-json”重新生成对象

function refReplacer() {
  let m = new Map(), v= new Map(), init = null;

  return function(field, value) {
    let p= m.get(this) + (Array.isArray(this) ? `[${field}]` : '.' + field); 
    let isComplex= value===Object(value)
    
    if (isComplex) m.set(value, p);  
    
    let pp = v.get(value)||'';
    let path = p.replace(/undefined\.\.?/,'');
    let val = pp ? `#REF:${pp[0]=='[' ? '$':'$.'}${pp}` : value;
    
    !init ? (init=value) : (val===init ? val="#REF:$" : 0);
    if(!pp && isComplex) v.set(value, path);
   
    return val;
  }
}




// ---------------
// TEST
// ---------------

// gen obj with duplicate references
let a = { a1: 1, a2: 2 };
let b = { b1: 3, b2: "4" };
let obj = { o1: { o2:  a  }, b, a }; // duplicate reference
a.a3 = [1,2,b];                      // circular reference
b.b3 = a;                            // circular reference


let s = JSON.stringify(obj, refReplacer(), 4);

console.log(s);
Run Code Online (Sandbox Code Playgroud)


nev*_*evf 5

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

  1. CircularJSON https://github.com/WebReflection/circular-json,其输出可用作.parse()的输入.它也适用于Browsers&Node.js另见:http://webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
  2. Isaacs json-stringify-safe https://github.com/isaacs/json-stringify-safe,它可能更具可读性,但不能用于.parse,仅适用于Node.js

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


小智 5

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

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

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


归档时间:

查看次数:

75759 次

最近记录:

5 年,9 月 前