存储位置
在JS中,对于简单数据类型,比如number、null、undefined、string、boolean来说
它们的值是存在栈中的
而对于复杂数据类型,比如Object(array,function,Date)等,它的具体内容是存放在堆中的,在栈中存放指向该引用类型的地址
赋值
知道了它存储的位置,对于赋值操作也就不难理解了
| 12
 3
 4
 5
 6
 
 | let arr = [1,2,3];let arr2 = arr;
 console.log(arr2);
 arr2[1] = 9;
 console.log(arr);
 console.log(arr2);
 
 | 
正是由于它们存储的是同一个地址,当改变其中一个副本的值的时候,另一个值也会随之改变
浅拷贝
数组浅拷贝
数组浅拷贝有许多原生的方法
比如:slice方法、concat方法、Array.from()等
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | let arr = [1, [2, 3], 4];let arr1 = arr.slice(0);
 let arr2 = [].concat(arr);
 let arr3 = Array.from(arr);
 arr2.push(9);
 arr2[1].push(6);
 console.log(arr1);
 console.log(arr2);
 console.log(arr3);
 
 | 
值得注意的是,ES6中的扩展运算符对于一维数组可以实现深拷贝,但是对于多维数组只能实现浅拷贝,对于对象同样如此
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | let arr = [1,2,3];let arr2 = [...arr];
 arr2.push(6);
 console.log(arr2);
 console.log(arr);
 let arr3 = [1,[3,4],2];
 let arr4 = [...arr3];
 arr4[1][0] = 8;
 console.log(arr3);
 console.log(arr4);
 
 | 
对象浅拷贝
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | let obj = {name:"zhangsan",
 hobby:['杀人','放火']
 }
 let obj2 = Object.assign({},obj);
 obj2.hobby[0] = '打游戏';
 obj2.name = 'lisi';
 console.log(obj);
 console.log(obj2);
 
 | 

手写浅拷贝
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | function shallowCopy(obj){let newobj = Array.isArray(obj)?[]:{}
 for(let i in obj){
 if(obj.hasOwnProperty(i)){
 newobj[i] = obj[i]
 }
 }
 return newobj
 }
 let obj = {
 name:"zhangsan",
 hobby:['杀人','放火']
 }
 let arr = [1,[2,3],4];
 let newarr = shallowCopy(arr);
 newarr[1][0] = 5;
 console.log(arr);
 console.log(newarr);
 let obj3 = shallowCopy(obj);
 obj3.hobby[1] = '睡觉'
 console.log(obj);
 console.log(obj3);
 
 | 

深拷贝
JSON.parse(JSON.stringify())
这是最简单也是最常用的一种方法
缺点:undefined、function、symbol会在转换过程中被忽略
| 12
 3
 4
 5
 6
 7
 8
 
 | let obj = {name:"zhangsan",
 hobby:['杀人','放火']
 }
 let obj2 = JSON.parse(JSON.stringify(obj));
 obj2.hobby[0] = '学习';
 console.log(obj);
 console.log(obj2);
 
 | 

手写深拷贝
用递归来实现,直到不属于复杂类型再返回
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | function deepClone(obj) {let type = Object.prototype.toString.call(obj).slice(8, -1);
 if (type === 'Object') {
 let newobj = {};
 for (let i in obj) {
 if (obj.hasOwnProperty(i)) {
 newobj[i] = deepClone(obj[i])
 }
 }
 return newobj;
 }
 if (type === 'Array') {
 let newarr = [];
 for (let i in obj) {
 if (obj.hasOwnProperty(i)) {
 newarr[i] = deepClone(obj[i])
 }
 }
 return newarr;
 }
 return obj;
 }
 let obj = {
 name: "zhangsan",
 hobby: ['杀人', '放火']
 }
 let obj2 = deepClone(obj);
 let arr = [1, 2, 3, [4, 5, 6]]
 let arr2 = deepClone(arr);
 arr2[3][1] = 8;
 obj2.hobby[0] = '学习';
 console.log(arr);
 console.log(arr2);
 console.log(obj);
 console.log(obj2);
 
 | 

然而实际上仍然存在一些问题,比如循环引用导致的爆栈以及Symbol类型的处理等(看以后是否填坑吧)
第三方插件
比如lodash的深拷贝