Клонировать объект, пропуская круговые ссылки с JavaScript - PullRequest
0 голосов
/ 02 апреля 2020

У меня есть этот код, основанный на цикле Крокфорда . js, но он выделяет намного больше, чем это должно быть из входного объекта. По какой-то причине он идентифицирует почти все, как уже было видно в кэше, и пропускает его.

Я не совсем уверен, в чем смысл WeakMap по сравнению с Set, так что это может быть частью проблема. Я пытался поменять их, но, похоже, ничего не изменилось.

Вот код. Я сделал его достаточно автономным, чтобы вы могли просто добавить его в консоль браузера.

const message = (function cloneWithoutCircularReferences(object) {
    const cache = new WeakMap();

    const clone = Array.isArray(object) ? [] : {};

    function getKeyOfObjectByPath(object, path) {
        return path.reduce(function(object, key) {
            return object[key];
        }, clone) || clone;
    }

    (function traverse(object, path = []) {
        try {
            for (const [key, value] of Object.entries(object)) {
                if (typeof object === "object" && object !== null) {
                    if (cache.has(object)) {
                        continue;
                    }

                    cache.set(object, path);

                    getKeyOfObjectByPath(object, path)[key] = Array.isArray(object[key]) ? [] : {};

                    traverse(value, [...path, key]);
                } else {
                    getKeyOfObjectByPath[key] = value;
                }
            }
        } catch (error) { }
    })(object);

    return clone;
})(globalThis); // I'm using `globalThis` since it's an easily accessible object with circular references. The actual object I want to decircularize is an array of doubly linked objects.

console.log(message);

Вот снимок экрана указанного объекта c, который я пытаюсь decircularize. Обратите внимание, что ключ next является ссылкой на следующий объект в двусвязном списке.

Кроме того, subject указывает на объект window, так что он также будет содержать некоторые циклические ссылки.

enter image description here


Желаемый выход:

enter image description here

1 Ответ

0 голосов
/ 05 апреля 2020

Я закончил поиск в ширину, установил для кеширования видимых значений и добавил возможность занести в черный список ключи и ограничить глубину обхода.

Я не был в восторге от необходимости добавлять эти варианты, но дети были достаточно уникальны, чтобы пройти через кеш.

(function cloneWithoutCircularReferences(object, options) {
    const cache = new Set([window]);

    function getKeyOfObjectByPath(object, path) {
        return path.reduce(function(object, key) {
            return object[key];
        }, clone) || clone;
    }

    const clone = Array.isArray(object) ? [] : {};

    for (const queue = [{ "path": [], "node": object }]; queue.length !== 0;) {
        const { path, node } = queue.shift();

        for (const [key, value] of Object.entries(node)) {
            if (typeof value === "object" && value !== null) {
                if (cache.has(value) || options.blacklistedKeys.includes(key) || path.length >= options.maxLength) {
                    continue;
                }

                cache.add(value);

                queue.push({
                    "path": [...path, key],
                    "node": value
                });

                getKeyOfObjectByPath(clone, path)[key] = Array.isArray(object) ? [] : {};
            } else {
                try {
                    getKeyOfObjectByPath(clone, path)[key] = value;
                } catch (error) { }
            }
        }
    }

    return clone;
})(message, options);
...