Вот пример структуры данных с циклическими ссылками:
function makeToolshed(){
var nut = {name: 'nut'}, bolt = {name: 'bolt'};
nut.needs = bolt; bolt.needs = nut;
return { nut: nut, bolt: bolt };
}
Если вы хотите сохранить циклические ссылки (восстановить их при десериализации, вместо того, чтобы «обнулять» их), у вас есть 2 варианта, которые я сравню здесь. Первый - это цикл Дугласа Крокфорда. Второй - моя Сибирь. пакет. Оба работают, сначала «дециклируя» объект, т. Е. Создавая другой объект (без каких-либо циклических ссылок), «содержащий ту же информацию».
Мистер Крокфорд идет первым:
JSON.decycle(makeToolshed())
Как видите, вложенная структура JSON сохраняется, но есть новая вещь - объекты со специальным $ref
свойством. Посмотрим, как это работает.
root = makeToolshed();
[root.bolt === root.nut.needs, root.nut.needs.needs === root.nut]; // retutrns [true,true]
Знак доллара обозначает корень. .bolt
сказав $ref
нам, что .bolt
это «уже увиденный» объект, а значение этого специального свойства (здесь строка $ ["nut"] ["needs"]) говорит нам где, см. сначала ===
выше. Аналогично для второго $ref
и второго===
выше.
Давайте используем подходящий тест глубокого равенства (а именно функцию Андерса Касерга deepGraphEqual
из принятого ответа на этот вопрос ), чтобы проверить, работает ли клонирование.
root = makeToolshed();
clone = JSON.retrocycle(JSON.decycle(root));
deepGraphEqual(root, clone) // true
serialized = JSON.stringify(JSON.decycle(root));
clone2 = JSON.retrocycle(JSON.parse(serialized));
deepGraphEqual(root, clone2); // true
Теперь сибирь
JSON.Siberia.forestify(makeToolshed())
Сибирь не пытается имитировать «классический» JSON, без вложенной структуры. Граф объектов описан «плоско». Каждый узел графа объекта превращается в плоское дерево (список пар значений простых ключей со значениями только для целых чисел), которое является записью в .forest.
нулевом индексе, мы находим корневой объект, в более высоких индексах мы находим другие узлы граф объекта и отрицательные значения (некоторого ключа некоторого дерева леса) указывают на atoms
массив (который набирается через массив типов, но здесь мы пропустим детали ввода). Все терминальные узлы находятся в таблице атомов, все нетерминальные узлы находятся в таблице леса, и вы можете сразу увидеть, сколько узлов имеет граф объекта, а именно forest.length
. Давайте проверим, работает ли это:
root = makeToolshed();
clone = JSON.Siberia.unforestify(JSON.Siberia.forestify(root));
deepGraphEqual(root, clone); // true
serialized = JSON.Siberia.stringify(JSON.Siberia.forestify(root));
clone2 = JSON.Siberia.unforestify(JSON.Siberia.unstringify(serialized));
deepGraphEqual(root, clone2); // true
сравнение
добавлю раздел позже.