js深浅拷贝

一.原因和区别:
javascript的基本类型有:字符串,数字,布尔,null,undefined,对象(数组,正则表达式,日期,函数) ,大致分为俩种:基本数据类型和引用数据类型

基本数据类型:数字,字符串,null,undefined
引用类型:对象

基本数据类型保存在栈内存中(保存在栈内存中的必须是大小固定的数据),如果是基本数据类型,则按值访问的,就是在操作基本类型时,直接修改变量的值.
引用类型保存在堆内存中(大小不固定,只能保存在堆内存中),如果是引用类型的的值,我们只是通过保存在变量中的引用类型的地址来操作实际对象

浅拷贝:
浅拷贝只是拷贝基本类型的数据,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,因此存在父对象被篡改的可能,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
深拷贝:
深拷贝会另外创造一个一模一样的对象,新对象跟原对象占用不同的内存空间,修改新对象不会改到原对象

二.实现深拷贝的方法

  1. slice
var arr1 = ['a', 'b'], arr2 = arr1.slice();
console.log(arr1); // ["a", "b"]
console.log(arr2); // ["a", "b"]
arr2[0] = 'c'; //修改arr2
console.log(arr1); // ["a", "b"]
console.log(arr2); // ["c", "b"]

此时,arr2的修改并没有影响到arr1,看来深拷贝的实现并没有那么难嘛。
2) concat

var arr1 = ['a', 'b'], arr2 = arr1. concat ();
console.log(arr1); // ["a", "b"]
console.log(arr2); // ["a", "b"]
arr2[0] = 'c'; //修改arr2
console.log(arr1); // ["a", "b"]
console.log(arr2); // ["c", "b"]
我们把arr1改成二维数组再来看看:
var arr1 = ['a', 'b', ['c', 'd']], arr2 = arr1.concat();
arr2[2][1] = 100;
console.log(arr1); //['a', 'b', ['c', 100]]
console.log(arr2); //['a', 'b', ['c', 100]]

咦,arr2又改变了arr1,看来slice()/concat()只能实现一维数组的深拷贝
3) 调用json内置方法先序列化为字符串,再解析还原成对象

newObj=JSON.parse(JSON.stringify(obj));

缺陷:JSON是一种表示结构化数据的格式,只支持简单值、对象和数组三种类型,不支持变量、函数或对象实例。所以我们工作中可以使用它解决常见问题,但也要注意其短板:函数会丢失,原型链会丢失,以及上面说到的所有缺陷。
4) 递归函数

//深拷贝的实现
  var deepClone = function(currobj){
    if(typeof currobj !== 'object'){
        return currobj;
    }
    if(currobj instanceof Array){
        var newobj = [];
    }else{
        var newobj = {}
    }
    for(var key in currobj){
        if(typeof currobj[key] !== 'object'){
            // 不是引用类型,则复制值
            newobj[key] = currobj[key];
        }else{
            // 引用类型,则递归遍历复制对象
            newobj[key] = deepClone(currobj[key])    
        }
    }
    return newobj
}

总结:
1.赋值运算符 = 实现的是浅拷贝,只拷贝对象的引用值;
2.JavaScript 中数组和对象自带的拷贝方法都是“首层拷贝”;
3.JSON.stringify 实现的是深拷贝,但是对目标对象有要求;
4.若想真正意义上的深拷贝,请递归。

### JavaScript 深拷贝浅拷贝区别及实现方式 #### 深拷贝浅拷贝区别 浅拷贝仅复制对象的第一层属性,而深拷贝递归地复制对象的所有层级。如果对象的属性本身是引用类型(如数组或对象),浅拷贝只会复制引用地址,而不会创建新的独立对象[^2]。 例如,使用浅拷贝时,修改原始对象中的嵌套对象会影响拷贝后的对象,因为它们共享相同的引用地址[^4]。 ```javascript let obj1 = { a: 1, b: { c: 2 } }; let obj2 = Object.assign({}, obj1); // 浅拷贝 obj2.b.c = 3; console.log(obj1.b.c); // 输出 3 ``` 相比之下,深拷贝会为嵌套的对象创建全新的实例,确保修改拷贝后的对象不会影响原始对象[^4]。 ```javascript let obj1 = { a: 1, b: { c: 2 } }; let obj2 = JSON.parse(JSON.stringify(obj1)); // 深拷贝 obj2.b.c = 3; console.log(obj1.b.c); // 输出 2 ``` #### 实现浅拷贝的方法 1. 使用 `Object.assign()` 方法可以实现浅拷贝,它将源对象的属性复制到目标对象中[^4]。 ```javascript let obj1 = { a: 1, b: { c: 2 } }; let obj2 = Object.assign({}, obj1); ``` 2. 使用扩展运算符 `...` 也可以实现浅拷贝[^4]。 ```javascript let obj1 = { a: 1, b: { c: 2 } }; let obj2 = { ...obj1 }; ``` #### 实现深拷贝的方法 1. **递归实现**:通过递归遍历对象的每个属性,逐一复制。这种方法适用于复杂对象结构,但需要处理循环引用问题[^3]。 ```javascript function deepCopy(obj) { if (obj instanceof Array) { var newObj = []; } else { var newObj = {}; } for (let i in obj) { if (typeof obj[i] === "object" && obj[i] !== null) { newObj[i] = deepCopy(obj[i]); } else { newObj[i] = obj[i]; } } return newObj; } ``` 2. **通过 `JSON` 对象实现深拷贝**:将对象转换为字符串后再解析为新对象。此方法简单高效,但无法处理函数、`undefined` `Date` 类型等特殊值[^2]。 ```javascript let obj1 = { a: 1, b: { c: 2 } }; let obj2 = JSON.parse(JSON.stringify(obj1)); ``` 3. **通过 jQuery 的 `extend` 方法实现深拷贝**:设置第一个参数为 `true` 即可启用深拷贝功能。 ```javascript let array = [1, 2, 3, 4]; let newArray = $.extend(true, [], array); ``` 4. **使用第三方库(如 Lodash)实现深拷贝**:Lodash 提供了 `_.cloneDeep` 方法,能够处理更复杂的对象结构[^1]。 ```javascript let obj1 = { a: 1, b: { c: 2 } }; let obj2 = _.cloneDeep(obj1); ``` 5. **改进的递归实现**:通过引入 `WeakMap` 处理循环引用问题,确保深拷贝的健壮性[^4]。 ```javascript function deepClone(obj, hash = new WeakMap()) { if (obj === null) return obj; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (typeof obj !== "object") return obj; if (hash.has(obj)) return hash.get(obj); let cloneObj = new obj.constructor(); hash.set(obj, cloneObj); for (let key in obj) { if (obj.hasOwnProperty(key)) { cloneObj[key] = deepClone(obj[key], hash); } } return cloneObj; } ``` #### 注意事项 - 浅拷贝仅适用于简单对象,对于嵌套对象可能引发意外行为。 - 深拷贝需要考虑性能问题,尤其是在处理大型或复杂对象时。 - 特殊类型(如 `Date`、`RegExp`、`Function`)在深拷贝时需要额外处理[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值