美文网首页
非递归深度复制

非递归深度复制

作者: yongningfu | 来源:发表于2017-03-21 02:12 被阅读0次

先上代码 来源

// 宽度优先遍历复制, 借助队列

/**
 * 整个算法思路为, 利用队列存储当前需要复制的对象记录
 * 取出队列的的元素,遍历复制属性
 * 1. 如果属性不为对象引用 那么直接赋值
 * 
 * 2. 如果为对象. 那么先创建一个新对象 并把这个对象利用key value存储当前复制的对象上面
 *    然后把当前创建的新对象加入到复制队列中 currentCopyElement[key] = {};
 *    这样的话,当复制队列元素进行复制的时候,由于是引用,则当前对象的属性值也会改变
 * 
 * 为了这里还用了 srcVisitedQueue 这个是用来记录访问过(复制)的对象的,它用于判断是否有循环
 * 引用,那如果单单是为了判断是否为循环引用的话,那么为何在复制队列上面还需要一个 copyVisitedQueue
 * 因为复制队列上面 所有的对象都是新创建的,不可能说如果有循环引用的话,就直接拿旧队列上面的对象
 */

function deepCopy(obj) {
    var newObj = {},

        /**创建4个必须的队列 */
        srcQueue = [obj], srcVisitedQueue = [],
        copyQueue = [newObj], copyVisitedQueue = [];

    while (srcQueue.length > 0) {

        //移出当前需要复制的对象
        var currentSrcElement = srcQueue.shift(),
            currentCopyElement = copyQueue.shift();
        
        //加入到已经访问过的队列中
        srcVisitedQueue.push(currentSrcElement);
        copyVisitedQueue.push(currentCopyElement);

        //进行属性的遍历 然后复制
        for (var key in currentSrcElement) {
            
            //不是对象 直接复制
            if (typeof currentCopyElement[key] !== 'object') {
                currentCopyElement[key] = currentSrcElement[key];

            //如果是对象的话 分为两种情况 
            } else {
                //判断是否有环
                var index = srcVisitedQueue.indexOf(currentSrcElement[key]);
                if (index >= 0) {
                  //有环的时候 直接取之前已经访问过的对象 不用重新创建
                    currentCopyElement[key] = copyVisitedQueue[index];
                } else {

                     //不是环的话,新创建一个新对象,然后保存当前对象的属性,再把当前创建的对象
                     //放入到复制队列中,进行属性的填充
                    srcQueue.push(currentSrcElement[key]);
                    currentCopyElement[key] = {};
                    copyQueue.push(currentCopyElement[key]);
                }
            }
        }
    }

    return newObj;
}

// Test case
// 1. 只含有简单类型的Object{a: 1, b:2} => pass
// 2. 简单类型和复杂类型同时存在的情况下的Object => pass:
// var obj1 = {
//     a: 1,
//     b: 2,
//     c: {
//         d: 3,
//         e: {
//             f: 4,
//             g: 5
//         }
//     },
//     h: {
//         i: 6,
//         j: 7
//     }
// };
// 3. 有环的情况下的Object => pass:
// var obj1 = {
//     a: 1,
//     b: 2,
//     c: obj1
// };

相关的注释已经直接放入代码,当然不否认源代码还有不少缺少考虑的东西,但是不能否认这个深度复制和判断是否有环的做法的精妙

相关文章

网友评论

      本文标题:非递归深度复制

      本文链接:https://www.haomeiwen.com/subject/wkdwnttx.html