2012-05-01 3 views
48

У меня есть определение объекта JavaScript, которое содержит циклическую ссылку: оно имеет свойство, которое ссылается на родительский объект.Stringify (конвертировать в JSON) объект JavaScript с круговой ссылкой

Он также имеет функции, которые я не хочу передавать на сервер. Как бы я сериализовал и десериализовал эти объекты?

Я читал, что лучший способ сделать это - использовать Дуглас Крокфорд. Тем не менее, я получаю следующее сообщение об ошибке в Chrome:

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.

Как сделать сериализацию перед отправкой на сервер и десериализовать ее при условии, что тот же JSON будет передан обратно?

ответ

90

Круговая структура ошибка возникает, когда у вас есть свойство объекта, который сам непосредственно объект (a -> a) или косвенно (a -> b -> a) ,

Чтобы избежать сообщения об ошибке, сообщите 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). Это, как правило, вызывает путаницу в будущем ...

9

Оказывается, что 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

+0

Привет, спасибо за ваш ответ. Я должен был сказать, что я использую jquery, поскольку моя библиотека. Я не думал, что это актуально в то время. Обновите мой пост. – user1012500

+0

@ user1012500 - Dojo отлично работает рядом с jQuery. Я часто включаю другие библиотеки или рамки, чтобы компенсировать недостатки в моей основной структуре. Вы даже можете извлечь методы 'toJson' и' fromJson' и создать вокруг них свою собственную обертку jQuery. Таким образом, вам не нужно будет тянуть всю структуру. К сожалению, jQuery не имеет этой функции из коробки, и JSON.stringify не может обрабатывать эти типы объектов. Поэтому, помимо приведенных выше примеров, вам, возможно, придется самостоятельно программировать эту функцию. –

+1

Привет Брэндон, я не решаюсь добавить еще одну библиотеку для решения проблемы, так как она добавляет еще один след на сайт. Однако я сделал додзё выстрелом и попытался использовать ваш пример против моего. Тем не менее, я столкнулся с круглой проблемой (я не очень хорошо разбираюсь в додзё, поэтому я только что попытался сделать пару вещей, но в основном основан на вашем примере): http://jsfiddle.net/Af3d6/1/ – user1012500

4

Я нашел два подходящих модуля для обработки круговых ссылок в 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. Айзекс JSON-stringify безопасный https://github.com/isaacs/json-stringify-safe, который может быть более удобным для чтения, но не может быть использован для .parse и доступен только для Node.js

Любой из них должен соответствовать вашим потребностям.

-9

Я использовал следующее для устранения циклических ссылок:

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

Это приведет к удалению экземпляров 'jQuery' и' HTMLElement', а не круговых ссылок? – ZachB

+0

@ZachB Я думаю, что в его настройке они круговые для него ... но проблема в том, что только потому, что javascript - это используемый язык, не означает, что у нас есть jquery или даже HTML-элементы. – moeiscool

0

Happened на эту тему, потому что мне нужно, чтобы войти сложные объекты на страницу, так как удаленная отладка не была возможна в моей конкретной ситуации. Найдено Douglas Crockford (inceptor of JSON) собственный cycle.js, который аннотирует круговые ссылки в виде строк, чтобы их можно было снова подключить после разбора. Децибельная глубокая копия безопасна для прохождения через JSON.stringify. Наслаждайтесь!

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

cycle.js: Этот файл содержит две функции, JSON.decycle и JSON.retrocycle, которые позволяют кодировать циклические структуры и группы DAG в формате JSON, а затем восстановить их. Это возможность, которую ES12 не предоставляет . JSONPath используется для представления ссылок.

Смежные вопросы