浅拷贝和深拷贝
当我们进行浅拷贝时,拷贝基本数据类型和引用数据类型的情况是不一样的。
为什么呢?因为两种情况下内存发生的变化不一样。
1、拷贝基本数据类型举例:
1 var video = 100; 2 var copy = video; 3 copy = 10000; 4 console.log(video); // 100 5 console.log(copy); // 10000
我们发现修改copy的值,不会影响video。
内存中发生什么呢?video相当于一个标识符,会为其分配一个内存地址,存储的值为100。拷贝给copy,vedio和copy都指向一个内存地址。然后给copy赋新值,会开辟新的内存地址。存在栈内存中。
2、拷贝引用数据类型举例:
1 var video = { 2 like: 100 3 }; 4 var copy = video; 5 copy.like = 10000; 6 console.log(video); 7 console.log(copy);
结果发现修改copy,会影响video。
此时内存发生什么呢?video相当于一个标识符,会为其分配一个栈内存地址,这个内存地址提供一个新的引用地址指向堆内存中的值。
我们可以通过什么方法进行浅拷贝?(注意是对象)
1、惯用的方法,即赋值法 2、通过Object.assign() ,从代码上可以看出前提是对象(当然了,基本数据类型虽然也不会报错)3、for...in(只循环第一层)
这里只提供下for...in的方法代码
1 function simpleCopy(obj1) { 2 var obj2 = Array.isArray(obj1) ? [] : {}; 3 for (let i in obj1) { 4 obj2[i] = obj1[i]; 5 } 6 return obj2; 7 } 8 var obj1 = { 9 a: 1, 10 b: 2, 11 c: { 12 d: 3 13 } 14 }; 15 var obj2 = simpleCopy(obj1); 16 obj2.a = 3; 17 obj2.c.d = 4; 18 console.log(obj1); 19 console.log(obj2);
深拷贝方法:
1、扩展运算符
(1)拷贝数组
1 var a = [1,2]; 2 var b = [...a]; 3 console.log(b) 4 b[0] = 11; 5 console.log(a) 6 console.log(b)
(2)拷贝对象
1 var obj = { 2 name: '小明', 3 age: 12 4 }; 5 var newObj = {...obj}; 6 console.log(newObj) 7 newObj.name = '小红'; 8 console.log(obj) 9 console.log(newObj)
2、使用JSON.parse(JSON.stringify())
1 var video = { 2 like: 100 3 }; 4 var copy = JSON.parse(JSON.stringify(video)); 5 copy.like = 10000; 6 console.log(video); 7 console.log(copy);
缺点:它是不可以拷贝 undefined , function, RegExp 等等类型的
拷贝失败案例1:function
1 <script type="text/javascript"> 2 var obj = { 3 name: '小明', 4 age: 6, 5 say: function() { 6 console.log('我会打篮球') 7 } 8 } 9 function deep(obj) { 10 return JSON.parse(JSON.stringify(obj)) 11 } 12 var newObj = deep(obj) 13 console.log(obj) 14 console.log(newObj) 15 </script>
结果1:
拷贝失败案例2:undefined
1 <script type="text/javascript"> 2 var obj = undefined 3 function deep(obj) { 4 return JSON.parse(JSON.stringify(obj)) 5 } 6 var newObj = deep(obj) 7 console.log(obj) 8 console.log(newObj) 9 </script>
结果2:
其它:
3、递归拷贝,封装一个函数(推荐)
1 let obj1 = { 2 a: { 3 c: /a/, 4 d: undefined, 5 b: null 6 }, 7 b: function () { 8 console.log(this.a) 9 }, 10 c: [ 11 { 12 a: 'c', 13 b: /b/, 14 c: undefined 15 }, 16 'a', 17 3 18 ] 19 } 20 let obj2 = deepClone(obj1); 21 console.log(obj1); 22 console.log(obj2);
封装的深拷贝函数如下:
1 // 定义一个深拷贝函数 接收目标target参数 2 function deepClone(target) { 3 // 定义一个变量 4 let result; 5 // 如果当前需要深拷贝的是一个对象的话 6 if (typeof target === "object") { 7 // 如果是一个数组的话 8 if (Array.isArray(target)) { 9 result = []; // 将result赋值为一个数组,并且执行遍历 10 for (let i in target) { 11 // 递归克隆数组中的每一项 12 result.push(deepClone(target[i])); 13 } 14 // 判断如果当前的值是null的话;直接赋值为null 15 } else if (target === null) { 16 result = null; 17 // 判断如果当前的值是一个RegExp对象的话,直接赋值 18 } else if (target.constructor === RegExp) { 19 result = target; 20 } else { 21 // 否则是普通对象,直接for in循环,递归赋值对象的所有值 22 result = {}; 23 for (let i in target) { 24 result[i] = deepClone(target[i]); 25 } 26 } 27 // 如果不是对象的话,就是基本数据类型,那么直接赋值 28 } else { 29 result = target; 30 } 31 // 返回最终结果 32 return result; 33 }