递归实现深层克隆

在整理前端面试问题的时候,遇到很多要求利用js实现深层克隆要求,因此特意回去翻看了资料,并将笔记和代码整理了一下。

关于深层克隆

深层克隆可以简单理解为:可以克隆第一级属性,如果某个属性又是一个内嵌的子对象,深克隆会进入子对象中,继续克隆内嵌子对象及其内容。

实现深层克隆的思路:
1、首先对需要克隆的对象进行遍历,判断里面属性值的类型
2、属性值的类型分为两种:原始值(string,number,null,undefine,boolean)和引用值(object,array)
3、如果遍历到的属性值为原始值,则直接进行拷贝
4、如果遍历到的属性值为引用值类型,则需要在目标对象的对应属性地方建立新的引用值类型,以原始引用值类型为模板,新建立的引用值为目标重复1,2,3步骤进行拷贝,从而实现深层拷贝。
下面给出代码实现过程:(附超详细注释)

function deepClone(origin,target){
            var target = target || {};
            toStr = Object.prototype.toString;
            arrStr = "[object.Array]";
            for (var key in origin) {
                // 判断是否为原型链上的值
                if (origin.hasOwnProperty(key)) {
                     // 判断当前的属性值类型是否为引用值
                    if(origin[key] !== "null" && typeof(origin[key]) == "object"){
                        // 当前引用值类型为引用值,调用原型链上的方法判断当前的属性值是否为数组
                        if(toStr.call(origin[key]) == arrStr){
                            // 根据当前属性值为数组类型,建立目标数组
                            target[key] = [];
                        } else{
                            // 当前属性值为对象类型,建立目标对象
                            target[key] = {};
                        }
                        // 以新建立的目标类型,对原始的引用值类型属性进行递归克隆,即重复步骤1,2,3,4
                        deepClone(origin[key],target[key]);
                    }
                    else{
                        // 当前的属性值类型不为引用值类型,为原始值,直接拷贝
                        target[key] = origin[key];
                    }
                    
                }
            }
        }
}

运行结果:

此处使用的深层拷贝算法可以很好的实现深层克隆,包括属性值为对象类型也可以完整克隆,下面验证当修改原始对象中的值时,对应的克隆对象中的值会不会发生改变:
在这里插入图片描述
当修改原始对象中的值时,此时克隆对象中的值并没有发生改变。这是由于虽然克隆的对象虽然由原始值而来,但是里面的引用值类型中保存的是自己独立的指针,指向被克隆出来的新房间,当原始房间中的值发生改变时,克隆出来的值不受原始值的影响。

在这里有几个扩展点:
1、当判断对应的值是否为数组或者对象时,除了文档中用到的对象原型链上的toString方法意外,还可以使用instanceof以及constructor方法。
2、为了在代码实现过程中,提高代码可读性,用到的toStr.call(Origin[prop]==‘arrStr’),其实就是判断是否是[object Array],将原型链上的tostring方法单独提了出来。

既然聊到了深层克隆,那么关于浅层克隆,也做一个简单的分析:

浅层克隆

实现被克隆对象的一一克隆,其中对引用值类型的克隆,就相当于克隆了其引用值中所保存的地址空间,克隆对象和被克隆对象中,指针指向的是同一个地址空间,当引用值改变时,两个克隆出来的对象中的值也跟着改变

function clone(Origin,Target){
    var Target = Target||{};//防止用户不传Target
    for ( prop in Origin){
        Target[prop]=Origin[prop]
        }
    return Target;
    }

在这里插入图片描述
当修改引用值中的数据时,其对应的克隆对象中的值也跟着变化:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42418196/article/details/107572146