Вот пример структуры данных с циклическими ссылками: ![toolshedCY](https://mathheadinclouds.github.io/img/shed.png)
function makeToolshed(){
var nut = {name: 'nut'}, bolt = {name: 'bolt'};
nut.needs = bolt; bolt.needs = nut;
return { nut: nut, bolt: bolt };
}
Если вы хотите СОХРАНИТЬ циклические ссылки (восстановить их при десериализации вместо уничтожения), у вас есть 2 варианта, которые я сравню здесь. Во-первых, это cycle.js Дугласа Крокфорда, во-вторых, мой < пакет href="https://github.com/mathHeadInClouds/siberia" rel="nofollow noreferrer">siberia. Оба работают, сначала дециклируя объект, т. е. создавая другой объект (без каких-либо циклических ссылок), содержащий ту же информацию.
Мистер Крокфорд идет первым:
JSON.decycle(makeToolshed())
![JSON_decycleMakeToolshed](https://mathheadinclouds.github.io/img/JSON_decycleMakeToolshed.png)
Как видите, вложенная структура 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_Siberia_forestify_makeToolshed](https://mathheadinclouds.github.io/img/JSON_Siberia_forestify_makeToolshed.png)
Сибирь не пытается имитировать классический 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
сравнение
раздел добавлю позже.
Примечание
В настоящее время я рефакторинг пакета. Основные идеи и алгоритмы остаются прежними, но новая версия будет проще в использовании, API верхнего уровня будет другим. Очень скоро я заархивирую siberia и представлю рефакторинговую версию, которую назову objectgraph. Оставайтесь с нами, это произойдет в этом месяце (август 2020 г.)
ну и ультракороткая версия для сравнения. Для указателя мне нужно столько места, сколько занимает целое число, поскольку мои указатели на уже видимые узлы (фактически, на все узлы, уже видимые или нет) являются просто целыми числами. В версии г-на Крокфорда количество, необходимое для хранения указателя, ограничено только размером графа объектов. Это делает наихудшую сложность версии мистера Крокфорда чрезвычайно ужасной. Мистер Крокфорд дал нам еще одну сортировку пузырьков. Я не шучу. Это так плохо. Если вы не верите, есть тесты, вы можете найти их, начиная с readme пакета (также в этом месяце, август 2020 г., они будут преобразованы для обеспечения совместимости с эталоном.js)
person
mathheadinclouds
schedule
12.11.2019
cycle.js
Дугласа Крокфорда в качестве ответа, так как это наиболее подходящее решение для многих случаев. Вам кажется уместным опубликовать этот ответ, поскольку вы первый, кто ссылается на него (в своем комментарии ниже). Если вы не хотите публиковать это как ответ самостоятельно, я в конечном итоге сделаю это. - person Jeremy   schedule 24.05.2013