【问题标题】:Clone an object, skipping circular references with JavaScript克隆一个对象,使用 JavaScript 跳过循环引用
【发布时间】:2020-04-02 14:51:35
【问题描述】:

我的这段代码基于 Crockford 的 cycle.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);

这是我尝试去环化的特定对象的屏幕截图。注意next 键是对双向链表中下一个对象的引用。

此外,subject 指向 window 对象,因此它也将包含一些循环引用。


期望的输出:

【问题讨论】:

  • 明显的问题是,在循环引用中,你不知道循环从哪里开始,你应该开始跳过一些东西
  • 请发布“我想要去循环化的实际对象 [that] 是一个双向链表/对象数组”以及您期望得到的结果。
  • @Bergi Done,尽我所能。
  • 我的意思是,您能否发布构建您遇到问题的结构对象的代码,以及所需的 JSON 输出?我真的不知道你想省略的 next 属性有什么特别之处
  • 我已经确定我真正需要的是一个基于 BFS 的克隆函数,它带有一个缓存来清除看到的元素。 DFS 在这里帮不了我。

标签: javascript clone circular-reference


【解决方案1】:

我最终进行了广度优先搜索,使用 Set 缓存看到的值,并添加了将键列入黑名单和限制遍历深度的功能。

我对必须添加这些选项并不感到兴奋,但孩子们的独特之处足以让他们通过缓存。

(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);

【讨论】:

    猜你喜欢
    • 2017-03-10
    • 2011-12-19
    • 2011-04-15
    • 2015-02-07
    • 1970-01-01
    • 2015-02-04
    • 2013-01-03
    • 2011-01-16
    • 2020-04-09
    相关资源
    最近更新 更多