前端 深拷贝和浅拷贝的异同

本文通过JavaScript示例对比深拷贝与浅拷贝的区别及应用场景,讲解了基本数据类型与复杂数据类型的拷贝差异,并介绍了如何利用AngularJS中的`angular.copy()`方法进行深拷贝。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说到深拷贝和浅拷贝,相信熟悉C和Java的同学们经常涉及到这两个概念
现在以JavaScript为例,讨论深拷贝和浅拷贝
首先这里给大家写一段代码,大家思考,每个代码块的打印的结果应该是什么:

var a=1,b;
b=a;
b++;
console.log(“a,”+a);
console.log(“b,”+b);
/////////////////////
var c=[1,2,3],d;
d=c;
d.splice(0,1);
console.log(“c,”+c);
console.log(“d,”+d);
/////////////////////
var e={
name:”Jill”,
age:20
},f;
f=e;
f.name=”Donny”;
f.age=32;
console.log(“e,”+angular.toJson(e,true));
console.log(“f,”+angular.toJson(f,true));

首先在第一块代码中,a的打印结果是1,b的打印结果是2
在第二块代码中,c和d的打印结果都是[2,3]
在第三块代码中,e和f的打印结果都是{name:Donny,age:32}
这里大家思考一个问题,为什么当a和b都是基本数据类型时,把a的值赋给b,并修改b的值,a的值却不变
而当c与d为数组类型时,把c的值赋给d,并操作d删除掉数组第一项时,c的值也一并被修改了
同理e与f为对象类型时,把e的值赋给f,修改e的值,f的值也一并被改掉了。其中的原理又是怎么样的
这里像a和b这种,其中一个变量的值赋给另一个变量,并修改另一个变量的值,不会影响前一个变量的情况就是深拷贝
如果我们把前一个变量的值赋给另一个变量,修改后者的值,同时一起影响了前者的值,这种就是浅拷贝
深拷贝由于不引用同一块内存地址,所以改变其中一个的值,并不会影响另一个,但是如果使用浅拷贝,虽然变量名称不同
但是引用的却是同一块内存地址,其中一个变量修改了这个内存地址中的值,另一个变量再次访问这块内存地址时,得到的也是修改后的值
Javascript中基本数据类型变量的相互赋值是使用深拷贝执行的,而像数组和对象这种复杂数据类型,使用的则是浅拷贝
项目开发中我们经常会用到多个controller之间传递数组或者对象,有时也会把数组或者对象类型的数据保存再service中供随时使用
这个时候如果使用浅拷贝会一并修改我们的数据源中的值,会导致数据异常,所以到底是使用深拷贝还是浅拷贝,大家要结合具体需求来判断
用Javascript实现深拷贝代码示例如下:
复制数组:
之前看过一篇文章讨论不同浏览器对不同方法复制数组支持速度的异同,最后的结论是建议使用concat()方法复制数组

var a=[1,2,3];
var b=a.concat();

对象的复制:

var a={
name:”Jill”,
age:20
};
var b={
name:”“,
age:””
};

b.name=a.name;
b.age=a.age;
大家从以上代码可以看出,数组的深拷贝比较简单,用concat()方法就可以,但是对象的深拷贝却要知道有哪些固定字段,
定义好对象后,还要一个字段一个字段的赋值,很麻烦,对不对

经常使用angularJS开发项目的我们,往往忽视了angularJS封装好的一系列方法,比如angular.isString(),angular.isNumber(),angular.isArray(),angular.isFunction()来判断各种类型,还在使用JS的typeof和instanceof的同学们一定要意识到这点
在这些angular封装好的方法中,其中有一个叫做angular.copy()的,它是用来实现深拷贝的一个方法,可以直接用这个方法深拷贝
对象,数组,undefined,null等类型,很强大,从此告别复制对象类型数组时的种种复杂
代码示例:

var a=[1,2,3];
var b=angular.copy(a);

var c={
name:”Jill”,
age:20
};
var d=angular.copy(c);

深拷贝之后,我们随意操作赋值后变量的值
深拷贝和浅拷贝不仅仅是JS这门语言中用到,用的不好,往浅了说影响项目开发,往深了说是不了解数据结构
所以弄懂深拷贝和浅拷贝的概念以及如何应用是非常重要的

<think>好的,用户想了解C、C++C#中的深拷贝浅拷贝。首先,我需要回忆这些概念在不同语言中的实现区别。可能需要分语言来解释,因为每个语言的内存管理机制不同。 首先,浅拷贝深拷贝的基本概念。浅拷贝是复制对象的成员值,包括指针,但指针指向的地址不变,所以新旧对象共享同一块内存。深拷贝则是完全复制,包括指针指向的内容,这样两个对象独立,互不影响。 接下来,要分别处理C、C++C#的情况。C语言中没有类的概念,主要是结构体指针操作。这时候浅拷贝就是直接赋值结构体变量,而深拷贝需要手动分配内存并复制内容。例如,结构体包含指针时,直接赋值会导致共享指针,修改一个会影响另一个,而深拷贝需要自己写函数来复制指针指向的数据。 然后是C++,因为涉及构造函数、拷贝构造函数析构函数。浅拷贝默认的拷贝构造函数是成员逐一复制,如果有指针成员,就会导致同样的问题。深拷贝需要在拷贝构造函数中手动分配内存并复制数据。需要提到深拷贝的正确实现方法,比如重载拷贝构造函数赋值运算符,避免内存泄漏悬空指针。 C#的情况不同,因为它是托管语言,有垃圾回收机制。但是值类型引用类型的区别很重要。对于引用类型,简单的赋值是浅拷贝,而深拷贝需要实现ICloneable接口或自定义方法,递归复制所有引用对象。可能需要提到MemberwiseClone方法用于浅拷贝,以及序列化反序列化实现深拷贝的方式。 还要注意不同语言中的例子,比如C中使用memcpy进行结构体浅拷贝的问题,C++中的默认拷贝构造函数自定义深拷贝,C#中的Clone方法序列化技巧。需要确保每个例子准确,语法正确,符合用户的要求。 用户可能想知道何时使用深拷贝浅拷贝,以及可能的问题。比如浅拷贝可能导致双重释放或内存泄漏,而深拷贝成本更高。在C#中,引用类型的浅拷贝可能更常见,但需要根据场景选择。 最后,确保回答结构清晰,分点说明每个语言的情况,用例子辅助解释,并总结异同点。同时遵循用户的格式要求,数学公式用$...$,独立公式用$$...$$,虽然这里可能不太需要数学公式,但如果有变量或代码示例,要正确格式化。</think>在C、C++C#中,深拷贝(Deep Copy)浅拷贝(Shallow Copy)是处理对象复制的两种核心策略,以下是分语言详解: --- ### 一、C语言中的实现 C语言通过结构体指针手动管理内存: ```c struct Data { int* arr; int size; }; // 浅拷贝:直接复制结构体(指针地址相同) struct Data d1 = {malloc(5*sizeof(int)), 5}; struct Data d2 = d1; // d2.arr 与 d1.arr 指向同一内存 // 深拷贝:手动复制指针内容 struct Data deepCopy(struct Data src) { struct Data dst; dst.arr = malloc(src.size * sizeof(int)); memcpy(dst.arr, src.arr, src.size * sizeof(int)); dst.size = src.size; return dst; } ``` --- ### 二、C++中的实现 C++通过拷贝构造函数运算符重载控制行为: ```cpp class MyClass { public: int* data; MyClass(int val) { data = new int(val); } // 浅拷贝(默认行为) MyClass(const MyClass& other) = default; // data指针被直接复制 // 深拷贝(手动实现) MyClass(const MyClass& other) { data = new int(*other.data); // 分配新内存并复制值 } ~MyClass() { delete data; } }; // 使用示例 MyClass obj1(10); MyClass obj2 = obj1; // 浅拷贝会导致双重释放错误(需深拷贝修复) ``` --- ### 三、C#中的实现 C#通过引用类型值类型区分行为: ```csharp class ReferenceType { public int Value; } // 浅拷贝:复制引用 ReferenceType original = new ReferenceType { Value = 42 }; ReferenceType shallowCopy = original; // 指向同一对象 // 深拷贝:复制对象内容 public static T DeepCopy<T>(T obj) { using (MemoryStream stream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, obj); stream.Position = 0; return (T)formatter.Deserialize(stream); } } ``` --- ### 四、关键对比表 | 特性 | 浅拷贝 | 深拷贝 | |---------------------|----------------------------------------------------------------------|----------------------------------------------------------------------| | **内存共享** | 复制指针/引用,共享同一内存 | 创建新内存,完全独立 | | **修改影响** | 修改副本会影响原对象 | 修改副本不影响原对象 | | **性能成本** | $O(1)$,仅复制引用 | $O(n)$,需遍历所有层级 | | **适用场景** | 只读数据、轻量级对象 | 需独立修改的复杂对象 | --- ### 五、何时选择? 1. **浅拷贝**:对象无嵌套引用或数据不可变时(如C#的字符串) 2. **深拷贝**:对象包含动态分配资源(如C/C++指针)或需完全独立副本时 > **注意**:C++中未正确实现深拷贝会导致内存泄漏或崩溃,C#中需注意循环引用问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值