首页 > 其他分享 >深拷贝

深拷贝

时间:2022-09-27 11:37:46浏览次数:54  
标签:obj 对象 objClone let key 拷贝

引用数据类型--名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,我们以上面浅拷贝的例子画个图:

当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。

而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。

 

那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了

 叁 ❀ 实现简单的深拷贝

1.我们怎么去实现深拷贝呢,这里可以递归递归去复制所有层级属性。

这么我们封装一个深拷贝的函数(PS:只是一个基本实现的展示,并非最佳实践)

复制代码
function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);
复制代码

可以看到

跟之前想象的一样,现在b脱离了a的控制,不再受a影响了。

这里再次强调,深拷贝,是拷贝对象各个层级的属性,可以看个例子。JQ里有一个extend方法也可以拷贝对象,我们来看看

let a=[1,2,3,4],
    b=a.slice();
a[0]=2;
console.log(a,b);

那是不是说slice方法也是深拷贝了,毕竟b也没受a的影响,上面说了,深拷贝是会拷贝所有层级的属性,还是这个例子,我们把a改改

let a=[0,1,[2,3],4],
        b=a.slice();
a[0]=1; a[2][0]=1; console.log(a,b);

拷贝的不彻底啊,b对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了a的控制,说明slice根本不是真正的深拷贝。

这里引用知乎问答里面的一张图

 

第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。

同理,concat方法与slice也存在这样的情况,他们都不是真正的深拷贝,这里需要注意。

2.除了递归,我们还可以借用JSON对象的parse和stringify

复制代码
function deepClone(obj){
    let _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
    return objClone
}    
let a=[0,1,[2,3],4],
    b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
复制代码

可以看到,这下b是完全不受a的影响了。

附带说下,JSON.stringify与JSON.parse除了实现深拷贝,还能结合localStorage实现对象数组存储。有兴趣可以阅读博主这篇文章。

localStorage存储数组,对象,localStorage,sessionStorage存储数组对象

3.除了上面两种方法之外,我们还可以借用JQ的extend方法。

$.extend( [deep ], target, object1 [, objectN ] )

deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝

target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。

object1  objectN可选。 Object类型 第一个以及第N个被合并的对象。 

let a=[0,1,[2,3],4],
    b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

可以看到,效果与上面方法一样,只是需要依赖JQ库。

标签:obj,对象,objClone,let,key,拷贝
From: https://www.cnblogs.com/qingshuihongye/p/16733938.html

相关文章

  • jQuery 的属性拷贝(extend)的实现原理是什么,如何实现深拷贝?
    在默认情况下,通过$.extend()合并操作不是递归的(浅拷贝);如果第一个对象的属性本身是一个对象或数组,那么它将完全用第二个对象相同的key重写一个属性。这些值不会被合并。然......
  • 使用js实现深拷贝原理
    //任何引用数据类型的值都需要挨个遍历,直到取到基本类型的值为止functiondeepClone(obj){    varcloneObj=Array.isArray(obj)?[]:{};    //判断......
  • 实现深度克隆拷贝
     //判断是否是某类型constisType=(obj,type)=>{if(typeofobj!=='object')returnfalse;consttypeString=Object.prototype.toString.call(obj);......
  • 【转载】Python的深浅拷贝以及应用场景
    深浅拷贝的原理深浅拷贝用法来自copy模块。导入模块:importcopy浅拷贝:copy.copy深拷贝:copy.deepcopy字面理解:浅拷贝指仅仅拷贝数据集合的第一层数据,深拷贝指拷贝数据......
  • 零拷贝
    零拷贝不是值得不拷贝,而是0次cpu拷贝。 传统拷贝一个文件并且通过网络IO发送一个文件的发送端文件拷贝过程需要经过 DMA拷贝->cpu拷贝->cpu拷贝-DMA拷贝 第一......
  • 【JAVA】普通IO数据拷贝次数的问题探讨
    最近看到网上有些文章在讨论JAVA中普通文件IO读/写的时候经过了几次数据拷贝,如果从系统调用开始分析,以读取文件为例,数据的读取过程如下(以缓存I/O为例):应用程序调用read函......
  • js深拷贝
    1.//深拷贝functiondeepclone(obj){letnewobj=Array.isArray(obj)?[]:{}for(letkeyinobj){if(typeofobj[key]==='object'){newobj[ke......
  • C# 实现对象的深浅拷贝的三种方式代码示例
    面试的时候经常被问到c#对象的深浅拷贝实现以及区别,今天我们就来讲一下深拷贝和浅拷贝到底是什么。首先我们讲讲浅拷贝,浅拷贝就是将对象中的所有字段复制到新对象中去,浅拷......
  • java ArrayList的深拷贝与浅拷贝
    一、前言:ArrayList是我们经常会用到的集合类,有时候我们为了要不改变原来的数据需要重新拷贝一个新的ArrayList,今天在使用ArrayList拷贝时遇到了一些问题,这里整理并记录一......
  • javascript: 复制对象时的深拷贝及浅拷贝(chrome 105.0.5195.125)
    一,js代码<html><head><metacharset="utf-8"/><title>测试</title></head><body><buttononclick="assign()">无效:变量直接赋值</button><br/><br/><br......