递归函数实现对象的深拷贝(JavaScript)

        (一)原码    

    <script>
        //创建一个对象
        var person = {
            name : 'bart',
            age :21,
            friend :[{name : '张三',age : 23},{name : '李四',age : 21},{name : '王五',age : 22}],
            hoddy : ['swimming','playing football','fishing running','listening'],
            family : {
                number : '1xxxxxxxxxx2',
                address : '中国'
            }
        }
        
        //利用递归函数,实现拷贝
        function deepCopy(copyObj){

            // 创建一个变量,先不确定变量类型,值为undefined
            var obj 

            //判断copyObj是否是一个数组类型
            if(Array.isArray(copyObj)){

                //如果符合条件则给 obj一个空数组
                obj = []

                //通过数组的遍历进行拷贝
                //由于数组的元素可以是任意数据类型,所以需要对内部在进行判断其数据类型
                //这样也就有了obj[i] = deepCopy(copyObj[i]),通过此语句回调函数,完成判断
                //直到对象遍历完,return obj直接退出deepCopy()函数
                for(var i = 0 ; i < copyObj.length ; i++){

                    //通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
                    obj[i] = deepCopy(copyObj[i])
                }

                //循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
                return obj

            //array和对象类型的typeof()值都是object,由于上面if已经判断了array
            //这里是用来判断copyObj是否是对象
            }else if(typeof copyObj === 'object'){

                //给obj一个空对象
                obj = {}

                //通过对象的遍历进行拷贝
                //由于对象的属性可以是任意数据类型,所以需要对内部在进行判断其数据类型
                //这样也就有了obj[key] = deepCopy(copyObj[key]),通过此语句回调函数,完成判断
                //直到对象遍历完,return obj直接退出deepCopy()函数
                for(var key in copyObj){

                    //通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
                    obj[key] = deepCopy(copyObj[key])
                }

                //循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
                return obj
            }else{

                //没有上面两种类型的数据,就可以返回到调用它的地方
                //如:obj[i] = deepCopy(copyObj[i])                       
                //obj[key] = deepCopy(copyObj[key])
                //当返回这个数据的时候说明这个属性到底了
                return copyObj
            }
        }
        //将要拷贝的对象作为实际参数,然后将返回值给var xin
        var xin = deepCopy(person)
        //遍历新的对象
        for(var key in xin){
            console.log(xin[key])
        }
        //对二者进行验证,如果实现深拷贝,则二者地址不同,改变一个的数据,另一个不会发生变化
        xin.age = 22
        console.log(xin.age)
        console.log(person.age)
    </script>

        (二)、解决思路

        对对象的深拷贝的难点在于对象的属性值可以是任意类型,而数组的元素可以是任意属性,这样也恰恰是解决它的办法。

        将每一数据都进行判断,判断的结果分为数组、对象、其他,对数组和对象进行再一次判断。为了方便也就有了递归函数,通过反复回调进行判断,直到既不会数组又不是对象的时候才会拷贝,最后通过return将拷贝成功的对象返回。

        (三)、核心代码

        

        function deepCopy(copyObj){

            // 创建一个变量,先不确定变量类型,值为undefined
            var obj 

            //判断copyObj是否是一个数组类型
            if(Array.isArray(copyObj)){

                //如果符合条件则给 obj一个空数组
                obj = []

                //通过数组的遍历进行拷贝
                //由于数组的元素可以是任意数据类型,所以需要对内部在进行判断其数据类型
                //这样也就有了obj[i] = deepCopy(copyObj[i]),通过此语句回调函数,完成判断
                //直到对象遍历完,return obj直接退出deepCopy()函数
                for(var i = 0 ; i < copyObj.length ; i++){

                    //通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
                    obj[i] = deepCopy(copyObj[i])
                }

                //循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
                return obj

            //array和对象类型的typeof()值都是object,由于上面if已经判断了array
            //这里是用来判断copyObj是否是对象
            }else if(typeof copyObj === 'object'){

                //给obj一个空对象
                obj = {}

                //通过对象的遍历进行拷贝
                //由于对象的属性可以是任意数据类型,所以需要对内部在进行判断其数据类型
                //这样也就有了obj[key] = deepCopy(copyObj[key]),通过此语句回调函数,完成判断
                //直到对象遍历完,return obj直接退出deepCopy()函数
                for(var key in copyObj){

                    //通过回调函数完成向下的拷贝,一层一层的判断,一层一层拷贝
                    obj[key] = deepCopy(copyObj[key])
                }

                //循环完毕,也就是拷贝完毕,obj就是拷贝完成的数据,返回obj
                return obj
            }else{

                //没有上面两种类型的数据,就可以返回到调用它的地方
                //如:obj[i] = deepCopy(copyObj[i])                       
                //obj[key] = deepCopy(copyObj[key])
                //当返回这个数据的时候说明这个属性到底了
                return copyObj
            }
        }

        创建一个函数,在函数中写入判断条件,这样就可以通过调用函数反复判断,通过if-else语句判断属性数据类型,通过deepCopy(copyObj[key])以及deepCopy(copyObject[i])语句完成属性的判断,直到运行return copyObj才能完成一个拷贝动作,也就是拷贝到了一个值,当完成遍历之后所有的数据都拷贝完毕了,return obj返回拷贝数据。

        (四)是判断数组在前还是判断对象在前问题

造成这个问题的主要原因在于数组类型和对象的typeof()都是object,由于Array.isArray()可以判断是否是数组,这样一来就一定是判断数组在前,判断对象在后,如果判断对象在前,则后面的判断数组会直接被覆盖掉,即使原对象中的属性存在数组也会以object输出,这个可以在f12开发者工具中查看。判断对象在前,数组在后,结果如图

 


版权声明:本文为weixin_53867427原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。