深拷贝vs浅拷贝深拷贝和浅拷贝都是针对引用类型的。JS中的变量类型分为值类型(基本类型)和引用类型;复制值类型会复制值,而引用类型的赋值会复制地址,最终两个变量指向同一个数据。//基本类型vara=1;变量b=a;一=2;控制台日志(a,b);//2,1,ab指向不同的数据//引用类型指向相同的数据vara={c:1};varb=a;a.c=2;console.log(a.c,b.c);//2,2都是2,ab指向同一条数据对于引用类型来说,ab会导致ab指向同一条数据,这里有时候修改其中一个,会影响到另一个。有时这可能不是我们想要的结果。如果我们不清楚这种现象,可能会造成不必要的错误。那么如何切断a和b的关系呢?你可以复制a的数据。根据复制的层次不同,可分为浅复制和深复制。浅拷贝只是一层拷贝,深拷贝是无限层拷贝。深拷贝和浅拷贝的根本区别在于是否真正获取对象的拷贝实体,而不是引用深拷贝,在计算机中开辟一个内存地址来存放拷贝的对象,而浅拷贝只指向被拷贝的对象内存地址,如果原地址中的对象改变了,浅拷贝的对象也会随之改变。vara1={b:{c:{}};vara2=shallowClone(a1);//浅克隆a2.b.c===a1.b.c//truevara3=clone(a1);//深度克隆a3.b.c===a1.b.c//false所谓浅拷贝只是拷贝了基本类型的数据,拷贝之后引用类型的数据也会被引用。我们称这种拷贝为“(浅拷贝)浅拷贝”。Object.assign({},obj1,obj2)浅拷贝实现函数shallowClone(source){vartarget={};for(variinsource){if(source.hasOwnProperty(i)){target[i]=source[i];}}returntarget;}深拷贝实现深拷贝的问题其实可以分解成两个问题,浅拷贝+递归,什么意思呢?假设我们有以下数据vara1={b:{c:{d:1}};稍微修改一下上面的浅拷贝代码,注意区别functionclone(source){vartarget={};for(variinsource){if(source.hasOwnProperty(i)){if(typeofsource[i]==='object'){target[i]=clone(source[i]);}//注意这里}else{target[i]=source[i];}}}returntarget;}其实上面的代码问题太多了,先举几个例子吧。参数没有测试。函数isObject(x){返回Object.prototype。toString.call(x)==='[objectObject]';}functionclone(source){if(!isObject(source))返回源;//xxx}判断对象是否逻辑不够严谨,没有考虑数组的兼容性递归方式最大的问题就是会爆栈。当数据层级很深时,栈就会溢出。方法:使用系统自带的JSON做一个深拷贝的例子。我们来看一下实现functioncloneJSON(source){returnJSON.解析(JSON.stringify(source));}但是cloneJSON也有缺点。它还在内部使用递归方法cloneJSON(createData(10000));//超出最大调用堆栈大小既然使用了递归,那么循环引用呢?没有无限循环导致的堆栈溢出。事实证明,JSON.stringify会在内部检测循环引用。就是我们上面提到的第一种破解循环引用的方法:循环检测vara={};a.a=a;cloneJSON(a)//UncaughtTypeError:ConvertingcircularstructuretoJSON如何在没有引用的情况下复制对象?对于数组,ES6有两种新的无引用复制方法。第一种方法:Array.from(tocopiedarray);vararr1=[1,2,3];vararr2=Array.from(arr1);arr1.push(4);alert(arr1);//1234警报(arr2);//123arr2.push(5);警报(arr1);//1234警报(arr2);//1235第二种类型:...vararr1=[1,2,3];vararr2=[...arr1];arr1.push(4);alert(arr1);//1234警报(arr2);//123arr2.push(5);警报(arr1);//1234警报(arr2);//1235第二种方法也可以用在行参数上面的函数中。functionshow(...arr1){//直接把参数的伪数组复制出来,做成真正的数组,这样就有数组的方法了。警报(arr1);//1234arr1.push(5);警报(arr1);//12345}显示(1,2,3,4)
