首先,咱们必须明确一点,就是JavaScript的变量能够分为如下两种类型:javascript
基本变量是直接按值存放的,存放在栈内存中的简单数据段,能够直接访问。java
存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另外一个位置。当须要访问引用类型(如对象,数组等)的值时,首先从栈内存中得到该对象的地址指针,而后再从堆内存中取得所需的数据。正则表达式
一个简单的例子数组
var a = 2;
var obj1 = {b:2};
var obj2 = obj1;
obj2.b = 3;
console.log(obj1.b); // 3
console.log(obj2.b); // 3
复制代码
那么问题就来了,有一些场景咱们须要将一个对象含的值所有Copy
给另外一个对象,这个时候若是只是简单的赋值操做,只是对指针进行了一个复制,而在堆内存区的值并无发生改变。因此咱们获得如下的结论:bash
深拷贝便是在堆内存区拷贝出一个对象来。函数
深拷贝是开辟一块新的内存地址,将原对象的各个属性逐个复制进去。对拷贝对象和源对象各自的操做互不影响。工具
以前一直有一个错误实现深拷贝的想法,就是遍历一个对象的k-v对并一一复制给另外一个对象即可以实现深拷贝。ui
可是是错误的,这个是浅拷贝(shallowCopy)spa
缘由很简单,当K-V
对里value
是Object
的时候,复制过去便仍然是复制引用。好比prototype
let obj = {
a: 1,
b:{
c: 2,
d: 3
}
}
let obj2 = {}
for(let item of Object.keys(obj)){
obj2[item] = obj[item]
}
obj2.b.d = 2;
obj.b.d // 此时obj.b.d 变成了2
复制代码
另一点
Object.assign
也是一个shallowCopy
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj1.a = 1;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
复制代码
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = JSON.parse(JSON.stringify(obj1));
obj2.b.c = 3;
console.log(obj2.b.c); // { a: 0 , b: { c: 3}};
console.log(obj1.b.c); // { a: 0 , b: { c: 0}};
复制代码
该方法够处理JSON格式能表示的全部数据类型,可是没法拷贝对象里面的函数
,正则表达式
等,并且会丧失全部的constructor
,也就是说,将是破坏整条prototype
链。
刚才提到浅拷贝只能拷贝对象的一层,那么对浅拷贝进行递归即可以实现深拷贝。
function deepCopy (oldObj, newObj){
for(let key in oldObj){
if(typeof oldObj[key] != 'object'){
// 是基本类型直接复制
newObj[key] = oldObj[key];
}else {
newObj[key] = oldObj[key].constructor == '[Function: Array]'?[]:{};
deepCopy(oldObj[key],newObj[key])
}
}
}
复制代码
arguments.calle
能够在匿名函数中实现递归,此处也能够用deepCopy(oldObj[key],newObj[key])
,该方法的缺陷是,一旦欲拷贝对象和原对象存在相互引用的状况,即可能形成死循环。(一直往下递归仍然判断为Object即形成死循环)因此须要加上判断跳出的语句
...
for(let key in oldObj){
if(newObj[key] === oldObj[key]){
continue;
}
...
}
...
复制代码
loadash
loadash
有一个.cloneDeep
的方法能够实现深拷贝。
使用方法:
obj2 = _.cloneDeep(obj1);
浅拷贝
(shallowCopy)