手写深拷贝

139 阅读2分钟

众所周知,在Javascript中对象的直接赋值都是浅拷贝,也就是说,直接赋值的话,两个变量指向同一个对象地址,只要其中一个变量改变了对象的值,另一个变量指向对象中的值也会随之改变,所以深拷贝在Javascript中就显得格外重要,下面,我将一步步手写深拷贝代码。

先看完整代码

const deepClone=function (origin,target){
    const tar=target || {}
    const toStr=Object.prototype.toString
    const typeArray="[object,Array]"
    for(const k in origin){
        if(origin.hasOwnProperty(k)){
            if(typeof origin[k] ==="object" && origin[k]!==null)
            {
                tar[k]=toStr.call(origin[k]) === typeArray ? []:{}
                deepClone(origin[k],tar[k])
            }
            else{
                tar[k]=origin[k]
            }
        }
    }
    return tar
}

首先我们要明白一点,我们深拷贝的对象可能是嵌套的,也就意味着对象中可能会包含着对象,所以,我们手写的深拷贝函数一定是递归函数!所以,我们在构建深拷贝函数的时候一定要定义两个传参,一个是origin(源对象参数),另一个是target(需要拷贝至的对象参数)。

我们利用for循环遍历origin源对象中的每一项,并且需要用到hasOwnProperty这个对象中的API去过滤点原型上的属性

hasOwnProperty()  方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。

如果 k 是源对象中的属性,则我们需要判断 origin[k] 是不是object(对象),这里我们使用typeof方法去判断k的类型,(其中null的类型为object,所以在这里我们需要特地说明 origin[k] !== null)

当我们判断出 origin[k]为object的类型时,我们需要进一步判断是为数组(Array)类型还是对象(Object)类型,在这里我们用到 Object.prototype.toString方法,这个方法我们放到函数内用变量维护 即:

const toStr=Object.prototype.toString

我们的目标拷贝对象也需要我们用变量维护,默认为对象类型{} ,如果传参则为target 即:

const tar=target || {}

然后调用变量维护的toStr方法,用call方法调用(call方法的第一个参数为this指针),所以我们传入origin[k],将toStr方法中的this指针指向origin[k] 如果该方法返回的是"[object,Array]"则为数组类型,反之为对象类型("[object,Object]"),判断出类型后,我们需要将类型赋值给tar[k],其中"[object,Array]"常量值也用变量去维护,则:

const typeArray="[object,Array]"

当判断出tar[k]的类型时,我们再一次调用deepClone函数即可,切记一定要传参!(源对象以及目标对象)

如果我们判断出的 origin[k] 类型不是object类型,则可以直接tar[k]=origin[k]

最后 return 出 tar变量即可。