乐趣区

广度优先遍历实现js对象深拷贝

问题

一般我们实现深拷贝都是用递归的方式,但是递归缺点就是容易内存泄漏,因为当 js 对象嵌套很深的层级的时候就容易出问题,那解决这个问题就可以用循环的方式。广度优先遍历很适合做深拷贝,因为它是先遍历完一层的数据后再遍历下一层

实现方法

 function isObject(val) {if (Object.prototype.toString.call(val) === '[object Object]') return true;
            return false;
        }
        function isArray(val) {return Array.isArray(val);
        }
        function isFunction(val){if (Object.prototype.toString.call(val) === '[object Function]') return true;
            return false;
        }
        function deepCopy(jsonObj) {if (!isArray(jsonObj) && !isObject(jsonObj)) return jsonObj;
            let copy = {};
            let queue = [];
            let visited = {};
            queue.push({
                key: 'root',
                value: jsonObj,
                parent: copy // 根节点 parent 就是 copy
            });
        
            while (queue.length != 0) {const first = queue.shift();
                const parent = first.parent;
                if(visited[first.key] === first.value)continue;// 如果已将访问过则不处理
                if ((isArray(first.value) || isObject(first.value))) {for (let [key, value] of Object.entries(first.value)) {if (isArray(value) || isObject(value)) {
                            let childParent;
                            if (isObject(value)) {childParent = {};
                            }
                            else if (isArray(value)) {childParent = [];
                            }
                            queue.push({
                                key: key,
                                value: value,
                                parent: childParent // 重新声明一个 parent
                            });
                            parent[key] = childParent;// 连接新的 parent 和旧的 parent
                        }
                        else {
                            queue.push({
                                key: key,
                                value: value,
                                parent: parent
                            });
                        }
                    }
                } else {parent[first.key] = first.value;
                }
                visited[first.key] = first.value;
            }
            return copy;

        }

测试

        let obj1 = {
            e: 2,
            a:{b:44}
        }
        // 模拟循环引用,并没有爆栈哦
        obj1.o = {m:obj1};
        const obj2 = deepCopy(obj1);
        obj1.a.b = 100;
       console.log(obj2.a.b)// 打印 44, 说明 obj1 的改变没有影响 obj2,
退出移动版