jquery Stringify(转换为JSON)一个带有循环引用的JavaScript对象

ki1q1bka  于 2023-08-04  发布在  jQuery
关注(0)|答案(6)|浏览(115)

我有一个JavaScript对象定义,其中包含一个循环引用:它具有引用父对象的属性。
它还有一些我不想传递给服务器的函数。如何序列化和反序列化这些对象?
我读过这样做的最好方法是使用道格拉斯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的情况下进行反序列化?

xtfmy6hx

xtfmy6hx1#

循环结构当对象的属性直接(a -> a)或间接(a -> b -> a)为对象本身时,会发生错误。

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

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

字符串
stringify的第二个参数是 *filter函数 *。在这里,它只是将引用的对象转换为它的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)中的保留字。这往往会造成混乱的道路上...

zsbz8rwp

zsbz8rwp2#

No-lib

使用下面的replacer生成带有字符串引用的json(类似于json-path)来复制/循环引用对象

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

字符串

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

  // in TypeScript add "this: any" param to avoid compliation errors - as follows
  //    return function (this: any, field: any, value: any) {
  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);


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

function parseRefJSON(json) {
  let objToPath = new Map();
  let pathToObj = new Map();
  let o = JSON.parse(json);
  
  let traverse = (parent, field) => {
    let obj = parent;
    let path = '#REF:$';

    if (field !== undefined) {
      obj = parent[field];
      path = objToPath.get(parent) + (Array.isArray(parent) ? `[${field}]` : `${field?'.'+field:''}`);
    }

    objToPath.set(obj, path);
    pathToObj.set(path, obj);
    
    let ref = pathToObj.get(obj);
    if (ref) parent[field] = ref;

    for (let f in obj) if (obj === Object(obj)) traverse(obj, f);
  }
  
  traverse(o);
  return o;
}


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

let s = `{
    "o1": {
        "o2": {
            "a1": 1,
            "a2": 2,
            "a3": [
                1,
                2,
                {
                    "b1": 3,
                    "b2": "4",
                    "b3": "#REF:$.o1.o2"
                }
            ]
        }
    },
    "b": "#REF:$.o1.o2.a3[2]",
    "a": "#REF:$.o1.o2"
}`;

console.log('Open Chrome console to see nested fields:');
let obj = parseRefJSON(s);

console.log(obj);

j2cgzkjk

j2cgzkjk3#

dojo似乎可以用以下形式表示JSON中的循环引用:第一个月
下面是一个示例:
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

2ekbmq32

2ekbmq324#

我发现了两个合适的模块来处理JSON中的循环引用。

  1. CircularJSON https://github.com/WebReflection/circular-json,其输出可用作.parse()的输入。它也适用于浏览器和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
    这两个都应该满足你的需求。
pnwntuvh

pnwntuvh5#

因为我需要将复杂的对象记录到一个页面上,而在我的特定情况下,远程调试是不可能的。找到了道格拉斯Crockford(JSON的创始人)自己的cycle.js,它将循环引用注解为字符串,以便在解析后可以重新连接。去循环的深度副本可以安全地通过JSON. stringify。好好享受吧!
https://github.com/douglascrockford/JSON-js
js:这个文件包含两个函数,JSON.decycle和JSON.retrocycle,这使得在JSON中编码循环结构和dag,然后恢复它们成为可能。这是ES 5没有提供的功能。JSONPath用于表示链接。

webghufk

webghufk6#

我使用以下方法来消除循环引用:

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));

字符串

相关问题