浅谈浅拷贝和深拷贝
理解浅拷贝和深拷贝
js中的数据可以大致分为两种类型:基本数据类型和引用数据类型。
基本数据类型:基本数据类型的变量的赋值,可理解为深拷贝,修改其中一个数据,另一个数据不会随之变化
引用数据类型:引用数据类型分为key和value,它们两个分开存储,数据的值value在内存中,而指针key指向内存中的value值;引用数据类型的数据进行赋值,其实只是拷贝了数据的指针key,两个key指向的是同一个内存中的同一个值,修改其中一个指针对值的修改,另一个数据的值也会随着更改。
浅拷贝方法
浅拷贝拷贝的是地址,如果有对象嵌套,深层对象就会存在修改覆盖的问题- 数组的slice(start,end)
- 数组的concat方法
- 运用展开运算符====推荐
- Object.assign()
var a1 = {name: "yiyi", age: 18}; var a2 = Object.assign({}, a1); a2.name = "test"; console.log(a1);//{name: "yiyi", age: 18} console.log(a2);//{name: "test", age: 18} //============展开运算符===================== //我们也可以使用ES6的写法 var a3 = {name: "yiyi", age: 18}; var a4 = {...a3}; a4.name = "test2"; console.log(a3);//{name: "yiyi", age: 18} console.log(a4);//{name: "test2", age: 18}//============concat()============== var a1 = [1,2,3]; var a2 = a1.concat(); a1[0] = 2; console.log(a1);// [2,2,3] console.log(a2);//[1,2,3] //============展开运算符============== //我们也可以使用ES6的写法 var a1 = [2,2,2]; var a2 = [...a1]; a1[0] = 1; console.log(a1);// [1,2,2] console.log(a2);//[2,2,2] //========slice()========== var a1 = [3,4,5]; var a2 = a1.slice(); a1[0] = 1; console.log(a1);// [1,4,5] console.log(a2);//[3,4,5]如何实现浅拷贝
function shallowCopy(obj) { // 排除非对象或 null 的情况 if (typeof obj !== 'object' || obj === null) return obj; // 判断是数组还是普通对象,创建对应的新容器 const newObj = Array.isArray(obj) ? [] : {}; // 遍历并复制自身的可枚举属性 for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; }深拷贝方法
- JSON.stringify():对简单的对象深拷贝,不能拷贝具有方法,Symbol和不可枚举对象等
var o1 = {a: 1, b: 2, c: 3, family: {child: "child"}}; var o2 = JSON.parse(JSON.stringify(o1)); o1.a = 2; o2.family.child = "child2" console.log(o1); //{2,2,3, family: {child: "child"}} console.log(o2);//{1,2,3, family: {child: "child2"}}- JQuery库中的extend方法:$.extend( [deep ], target, object1 [, objectN ] )
- object1: 需要被合并的对象
- deep:表示是否进行深拷贝
- target: 合并后到该对象上
var o1 = {a: 1, b: 2, c: 3}; var o2 = $.extend(true,{},o1); o1.a = 2; console.log(o1); //{2,2,3} console.log(o2); //{1,2,3}如何实现深拷贝
function deepClone(obj, hash = new WeakMap()) { // 1. 处理基本类型和 null if (obj === null || typeof obj !== "object") return obj; // 2. 处理特殊内置对象(如 Date、RegExp) if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags); // 3. 解决循环引用:如果该对象已经被拷贝过,直接返回缓存 if (hash.has(obj)) return hash.get(obj); // 4. 根据原型创建对应的新容器(保持数组或普通对象的类型) const cloneObj = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj)); // 5. 存入缓存,防止后续递归产生死循环 hash.set(obj, cloneObj); // 6. 递归拷贝所有自身属性(包括 Symbol 属性) Reflect.ownKeys(obj).forEach(key => { cloneObj[key] = deepClone(obj[key], hash); }); return cloneObj; } // 测试循环引用 const original = { a: 1, b: { c: 2 } }; original.self = original; // 自己指向自己 const copy = deepClone(original); console.log(copy.self === copy); // 输出: true ✅ 完美处理循环引用========================================================================
简单介绍到这里,哈哈哈,这些真的是简单好用的方法,适合日常使用,关于多级对象和方法的拷贝,以后再整理
