js对象复制——浅拷贝、深拷贝

本文详细解析了JavaScript中对象赋值的原理,包括浅拷贝与深拷贝的区别,并提供了解决方案。通过实例演示了如何正确地对对象进行复制,避免了因直接赋值导致的引用问题。

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

一、场景

除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝

将一个对象赋值给另外一个对象。

var a = [1,2,3];
var b = a;
b.push(4); // b中添加了一个4
alert(a); // a变成了[1,2,3,4]  

自定义对象

var obj = {a:10};
var obj2 = obj;
obj2.a = 20; // obj2.a改变了,
alert(obj.a); // 20,obj的a跟着改变 

这就是由于对象类型直接赋值,只是将引用指向同一个地址,导致修改了obj会导致obj2也被修改

二、浅拷贝

所以,我们需要封装一个函数,来对对象进行拷贝,通过for in 循环获取基本类型,赋值每一个基本类型,才能真正意义上的复制一个对象

var obj = {a:10};
function copy(obj){
    var newobj = {};
    for ( var attr in obj) {
        newobj[attr] = obj[attr];
    }
    return newobj;
}
var obj2 = copy(obj);
obj2.a = 20;
alert(obj.a); //10  

这样就解决了对象赋值的问题。

三、深拷贝

但是这里存在隐患,如果obj中,a的值不是10,而是一个对象,这样就会导致在for in中,将a这个对象的引用赋值为新对象,导致存在对象引用的问题

var obj = {a:{b:10}};
function copy(obj){
    var newobj = {};
    for ( var attr in obj) {
        newobj[attr] = obj[attr];
    }
    return newobj;
}
var obj2 = copy(obj);
obj2.a.b = 20;
alert(obj.a.b); //20  

因此,由于这个copy对象只是对第一层进行拷贝,无法拷贝深层的对象,这个copy为浅拷贝,我们需要通过递归,来拷贝深层的对象。将copy改造成递归即可

var obj = {a:{b:10}};
function deepCopy(obj){
    if(typeof obj != 'object'){
        return obj;
    }
    var newobj = {};
    for ( var attr in obj) {
        newobj[attr] = deepCopy(obj[attr]);
    }
    return newobj;
}
var obj2 = deepCopy(obj);
obj2.a.b = 20;
alert(obj.a.b); //10   
### JavaScript 中深拷贝浅拷贝的区别 在 JavaScript 编程中,当涉及对象或数组的复制时,区分深拷贝浅拷贝至关重要。对于基本类型的变量(如字符串、数字),简单的赋值操作即可完成真正的副本创建;但对于复合类型的数据结构(比如对象和数组),情况则更为复杂。 #### 浅拷贝 (Shallow Copy) 浅拷贝是指创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝。如果这些属性也是对象,则只会复制其引用而是实际的内容[^1]。这意味着,在浅拷贝的情况下,源对象与其副本之间的嵌套对象仍然共享相同的内存位置。因此,修改其中一个对象内的任何深层成员都会反映到另一个对象上。 ```javascript let obj1 = { a: 1, b: { c: 2 } }; let shallowCopyObj = Object.assign({}, obj1); shallowCopyObj.b.c = 3; console.log(obj1.b.c); // 输出:3 ``` 上述代码展示了浅拷贝的行为——`obj1` 和 `shallowCopyObj` 的 `b` 属性实际上指向同一个内部对象实例。 #### 深拷贝 (Deep Copy) 相比之下,深拷贝复制最外层的对象本身,还会递归地复制对象内所有的子对象及其后续层次上的每一个元素,直到整个树状结构都被完全克隆为止[^3]。这确保了即使是最深层次的属性也会被两个同的对象所共有,从而实现了真正独立的新实体。 ```javascript function deepClone(source) { if (!source || typeof source !== 'object') return source; let result = Array.isArray(source) ? [] : {}; for (const key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { result[key] = deepClone(source[key]); } } return result; } let obj2 = { d: 4, e: { f: 5 } }; let deepClonedObj = deepClone(obj2); deepClonedObj.e.f = 6; console.log(obj2.e.f); // 输出:5 ``` 这段自定义函数 `deepClone()` 使用递归来遍历并复制传入对象的所有级别,最终得到一个全新的依赖于原有对象的状态。 除了手动编写递归逻辑之外,还可以利用 JSON 序列化/反序列化的技巧来简化某些场景下的深拷贝过程: ```javascript let originalArray = [{ g: 7 }]; let clonedArrayViaJson = JSON.parse(JSON.stringify(originalArray)); clonedArrayViaJson[0].g = 8; console.log(originalArray[0].g); // 输出:7 ``` 需要注意的是,这种方法并适用于所有情况,特别是那些含有循环引用或其他特殊特性的对象。 另外,也可以借助像 Lodash 这样的实用工具库提供的 `_.cloneDeep()` 方法来进行更可靠的深拷贝操作[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值