JavaScript -深拷贝函数封装

17 篇文章 0 订阅
本文详细探讨了JavaScript中的深拷贝和浅拷贝概念,通过实例展示了两者的区别。文章还提供了一个自定义的深拷贝实现方法,用于处理复杂对象的拷贝,确保修改新对象不会影响原始对象。同时,文中讨论了在实际编程中如何选择合适的拷贝方式,以避免潜在的引用问题。
摘要由CSDN通过智能技术生成

深拷贝与浅拷贝区别
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存; 改变一个对象,另一个会随之改变;
深拷贝:复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。

浅拷贝实现

var arr = [1, 2, 3, 4];

var arr2 = arr;
arr2[0] = "okokok"; 
console.log(arr); // ["okokok", 2, 3, 4]
console.log(arr2); // ["okokok", 2, 3, 4] 

像这样简单的赋值便是浅拷贝,一个对象改变,另一个也随之改变。

如何实现深拷贝 下面封装一个方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
         //数据
        var obj={
            a:1,
            b:"aaa",
            c:false,
            d:{
                e:[3,4,6,8,9],
                f:null,
                g:[
                    {id:1,name:"abc",price:100,tag:["自营","特价"]},
                    {id:2,name:"def",price:200,tag:["自营"]},
                    {id:3,name:"ghi",price:300,tag:["自营","特价","双十一"]},
                    {id:4,name:"gkl",price:400,tag:["专柜","双十一"]}
                ],
                h:{
                    i:/^(?=\D+\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,16}$/i,
                    j:new Date(),
                    k:{

                    }
                }
            }
        }
        Object.defineProperties(obj.d.h.k,{
            l:{
                value:[
                [1,2,3,4],
                [1,4,3,4],
                [1,6,3,4],
                ]
            },
            m:{
                enumerable:true,
                value:document.createElement("div")
            },
            n:{
                writable:true,
                value:{
                    o:[1,2,3],
                }
            }
        })
        
        //封装方法
        function cloneObj(source,target){
            // 如果目标对象不存在,根据源对象的类型创建一个目标对象
            if(!target) target=new source.constructor();
            // 获取源对象的所有属性名,包括可枚举和不可枚举
            var names=Object.getOwnPropertyNames(source);
            // 遍历所有属性名
            for(var i=0;i<names.length;i++){
                // 根据属性名获取对象该属性的描述对象,描述对象中有configurable,enumerable,writable,value
                var desc=Object.getOwnPropertyDescriptor(source,names[i]);
                // 表述对象的value就是这个属性的值
                // 判断属性值是否不是对象类型或者是null类型
                if(typeof desc.value!=="object" || desc.value===null){
                    // 定义目标对象的属性名是names[i],值是上面获取该属性名的描述对象
                    // 这样可以将原属性的特征也复制了,比如原属性是不可枚举,不可修改,这里都会定义一样
                    Object.defineProperty(target,names[i],desc);
                }else{
                    // 新建一个t对象
                    var t={};
                    // desc.value 就是源对象该属性的值
                    // 判断这个值是什么类型,根据类型创建新对象
                    switch(desc.value.constructor){
                        // 如果这个类型是数组,创建一个空数组
                        case Array:
                            t=[];
                        break;
                        // 如果这个类型是正则表达式,则将原值中正则表达式的source和flags设置进来
                        // 这两个属性分别对应正则desc.value.source 正则内容,desc.value.flags对应修饰符
                        case RegExp:
                            t=new RegExp(desc.value.source,desc.value.flags);
                        break;
                        // 如果是日期类型,创建日期类型,并且把日期值设置相同
                        case Date:
                            t=new Date(desc.value);
                        break;
                        default:
                        // 如果这个值是属于HTML标签,根据这个值的nodeName创建该元素
                            if(desc.value instanceof HTMLElement)
                                t=document.createElement(desc.value.nodeName);
                        break;
                    }
                    // 将目标元素,设置属性名是names[i],设置value是当前创建的这个对象
                    Object.defineProperty(target,names[i],{
                        enumerable:desc.enumerable,
                        writable:desc.writable,
                        configurable:desc.configurable,
                        value:t
                    });
                    // 递归调用该方法将当前对象的值作为源对象,将刚才创建的t作为目标对象
                    cloneObj(desc.value,t);
                }
            }
            return target;
        } 
       var o=cloneObj(obj);
       o.d.f="深拷贝"
       o.d.h.k.n.o[0]='深拷贝'
       console.log(obj);
       console.log(o); 
       
    </script>
</body>
</html>

在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值