Stringify (конвертировать в JSON) объект JavaScript с круглой ссылкой
У меня есть определение объекта 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 передан обратно?
Ответы
Ответ 1
Ошибка круговой структуры возникает, когда у вас есть свойство объекта, непосредственно являющегося объектом (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). Это, как правило, вызывает путаницу в будущем...
Ответ 2
Похоже, что 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
.
Другие ресурсы:
Как сериализовать DOM node в JSON, даже если есть круговые ссылки?
JSON.stringify не может представлять круговые ссылки
Ответ 3
Я нашел два подходящих модуля для обработки круговых ссылок в JSON.
Любой из них должен соответствовать вашим потребностям.
Ответ 4
Произошел этот поток, потому что мне нужно было записывать сложные объекты на страницу, поскольку удаленная отладка не была возможна в моей конкретной ситуации. Найден Douglas Crockford (inceptor of JSON) собственный cycle.js, который аннотирует круговые ссылки в виде строк, чтобы их можно было снова подключить после разбора. Децибельная глубокая копия безопасна для прохождения через JSON.stringify. Наслаждайтесь!
https://github.com/douglascrockford/JSON-js
cycle.js: этот файл содержит две функции: JSON.decycle и JSON.retrocycle, которые позволяют кодировать циклические структуры и проскакивает в JSON, а затем восстанавливает их. Это возможность, которая 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));