.什么是深拷贝和浅拷贝以及他们的区别

本文详细解释了深拷贝与浅拷贝的概念及其区别,并通过具体实例展示了这两种拷贝方式的工作原理。深入探讨了如何使用JavaScript实现这两种拷贝方法。

1.什么是深拷贝和浅拷贝以及他们的区别

深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
假设B复制了A,修改A的时候,看B是否发生变化:
如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)
如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)

浅拷贝实例:

//此递归方法不包含数组对象
var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);

function shallowCopy(src) {
  var newobj = {};
  for (var prop in src) {
    if (src.hasOwnProperty(prop)) {
      newobj[prop] = src[prop];
    }
  }
  return newobj;
}

因为浅复制只会将对象的各个属性进行复制,并不会进行递归复制,而JavaScript存储对象是存地址的,所以浅复制会导致Obj.arr和shallowObj.arr指向同一块内存地址:
在这里插入图片描述
导致的结果就是:

shallowObj.arr[1] = 5;
console.log(obj.arr[1]);     //5

深拷贝实例:

var obj = {
a:1,
arr: [1,2],
nation : '中国',
birthplaces:['北京','上海','广州']
};
var obj2 = {name:'杨'};
obj2 = deepCopy(obj,obj2);
console.log(obj2);
//深复制,要想达到深复制就需要用递归
function deepCopy(o, c){
var c = c || {};
for(var i in o){
if(typeof o[i] === 'object'){
if(o[i].constructor === Array){
//这是数组
c[i] = [];
}else{
//这是对象
c[i] = {};
}
deepCopy(o[i], c[i]);
}else{
c[i] = o[i];
}
}
return c;
}

而深复制则不同,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在obj和shallowObj的arr属性指向同一个对象的问题。
在这里插入图片描述
这样obj1和obj2分别拥有不同的内存地址,两边的值改变互不影响。

浅拷贝实现:

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

//因为b浅拷贝a, ab指向同一个内存地址(堆内存中存的值)
//b会随着a的变化而变化
//[2, 2, 3, 4, 5]
//[2, 2, 3, 4, 5]

在这里插入图片描述
深拷贝实现:

function deepClone(obj)
{
var newObj = obj instanceof Array ? []:{};
if(typeof obj !== 'object')
{
return obj;
}else{
for(var i in obj)
{
newObj[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
}
}
return newObj;
}
 
var a = [1, 2, 4, 6, "a", "12", [1, 2]];
var b = deepClone(a);
a[3] = 7;
console.log(a);
console.log(b);
//b对象并没有因为a对象的改变而改变,因为b深拷贝a
[ 1, 2, 4, 7, 'a', '12', [ 1, 2 ] ]
[ 1, 2, 4, 6, 'a', '12', [ 1, 2 ] ]

在这里插入图片描述

JavaScript 中的 `Object.assign()` 扩展运算符(`...`)均执行的是**浅拷贝**,而非深拷贝。这意味着它们在拷贝对象时,仅复制对象的第一层属性。如果属性值是引用类型(如对象或数组),则复制的是该值的引用地址,而非其实际内容。 ### `Object.assign()` 的拷贝行为 `Object.assign(target, ...sources)` 方法将一个或多个源对象的可枚举属性复制到目标对象中。它会直接修改目标对象并返回它。对于嵌套对象的属性,`Object.assign()` 仅复制引用,不会创建嵌套对象的副本。例如: ```javascript const source = { a: { b: 1 } }; const target = {}; Object.assign(target, source); console.log(target.a === source.a); // true,说明复制的是引用 ``` ### 扩展运算符(`...`)的拷贝行为 扩展运算符通过 `{ ...obj }` 创建一个新对象,并将源对象的可枚举属性复制到新对象中。与 `Object.assign()` 一样,它也仅执行浅拷贝。例如: ```javascript const source = { a: { b: 1 } }; const copy = { ...source }; console.log(copy.a === source.a); // true,说明复制的是引用 ``` ### 为什么是浅拷贝浅拷贝仅复制对象的第一层属性。对于基本类型的属性值,复制的是实际值;而对于引用类型的属性值(如嵌套对象),复制的是内存地址。因此,当嵌套对象被修改时,拷贝后的对象也会受到影响[^1]。例如: ```javascript const original = { a: { b: 1 } }; const copy = { ...original }; copy.a.b = 2; console.log(original.a.b); // 输出 2,说明原对象的嵌套属性被修改 ``` ### 如何实现深拷贝? 如果需要拷贝嵌套对象的所有层级,需使用深拷贝方法: 1. **使用 `JSON.parse(JSON.stringify(obj))`** 此方法通过序列化对象为 JSON 字符串,再解析字符串生成新对象。它适用于不含函数循环引用的对象: ```javascript const deepCopy = JSON.parse(JSON.stringify(original)); ``` 2. **使用递归函数** 递归遍历对象的所有层级,并为每个属性创建新对象或数组: ```javascript function deepClone(obj) { if (typeof obj !== 'object' || obj === null) return obj; let copy = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { copy[key] = deepClone(obj[key]); } } return copy; } ``` 3. **使用第三方库** 常用的库如 Lodash 提供了 `_.cloneDeep()` 方法实现深拷贝: ```javascript const _ = require('lodash'); const deepCopy = _.cloneDeep(original); ``` ### 总结 `Object.assign()` 扩展运算符(`...`)均执行浅拷贝,适用于简单对象的复制。如果对象包含嵌套结构,需要使用深拷贝方法(如 `JSON.parse(JSON.stringify(obj))`、递归函数或第三方库)以避免引用共享问题[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值