一、JS的数据类型
要想学习深浅拷贝,首先需要了解javascript的数据类型
javascript 中有两种数据类型,分别是基本数据类型(Number、String、Undefined、Boolean、Null、Symbol)和引用数据类型(对象、数组、函数)。
基本数据类型是按值访问的,操作的就是变量保存的值;如果是引用类型,则是通过保存在变量中的引用类型的地址来操作实际对象。
基本类型是不可变的,任何方法都无法改变一个基本类型的值,也不可以给基本类型添加属性或者方法。但是可以为引用类型添加属性和方法,也可以删除其属性和方法。
下面请看示例:
let num1 = 10;
let obj1 = {
name: "ding"
}
let num2 = num1;
let obj2 = obj1;
num2 = 20;
obj2.name = "bai";
console.log(num1); // 10
console.log(obj1.name); // bai
可以看出赋值的时候,基本类型是在栈内存中重新开辟内存,存放变量num2,所以在栈内存中存放的基本数据类型是不会相互影响的。引用类型复制的只是引用地址,指向的是堆内存中同一地址的同一对象,修改时会相互影响。
所以对于基本类型的拷贝,并没有深浅拷贝的区别,我们所说的深浅拷贝都是对于引用类型而言的。
二、浅拷贝
浅拷贝的意思就是只复制引用,而未复制真正的值,源对象和目标对象共享同一块内存,一个修改时另一个也跟着修改。上述代码就是利用 = 赋值操作实现的浅拷贝。也可以利用Object.assign或展开运算符 ...
来实现浅拷贝。
通过 Object.assign
实现,Object.assign第一级属性深拷贝,以后级别属性浅拷贝。
let a = {
age: 1,
name: { asd: "123" }
};
let b = Object.assign({}, a);
b.age = 2;
b.name.asd = "456";
console.log(a.age, a.name.asd); //1 ‘456’
通过展开运算符 ...
来实现深拷贝,但是需要注意的是,只针对对象的第一级属性有效
var arr = {
name: "aaa",
other: {
name: "bbb"
}
};
var arr2 = { ...arr };
arr2.name = "AAA";
arr2.other.name = "BBB";
console.log(arr); // { name: 'aaa', other: { name: 'BBB' } }
console.log(arr2); // { name: 'AAA', other: { name: 'BBB' } }
三、深拷贝
深拷贝实现的是真正意义上的对象的拷贝。深拷贝会创造一个一模一样的对象,其内容地址是自助分配的,拷贝结束之后,内存中的值完全相同,但是内存地址是不一样的,目标对象跟源对象不共享内存,修改任何一方的值,不会对另外一方造成影响。
可以通过JSON.parse(JSON.stringify(object))实现深拷贝:
var arr = {
name: "aaa",
other: {
name: "bbb"
}
};
var arr2 = JSON.parse(JSON.stringify(arr));
arr2.name = "AAA";
arr2.other.name = "BBB";
console.log(arr); // { name: 'aaa', other: { name: 'bbb' } }
console.log(arr2); // { name: 'AAA', other: { name: 'BBB' } }
实现原理:拷贝一个字符串会开辟一个新的存储地址,这样就切断了引用对象的指针联系,所以先转成一个字符串,在解析出对象,这样就可以深拷贝一个对象 。
补充:
JSON.parse(str) 用于从一个字符串中解析出 json 对象,JSON.stringify(obj)用于从一个对象解析出字符串。
自己实现一个深拷贝函数:
function deepClone(obj) {
let res;
if (typeof obj === 'object') {
if (obj === null) {
res = obj;
} else {
res = Array.isArray(obj) ? [] : {};
for (let key in obj) {
let val = obj[key];
res[key] = deepClone(val);
}
}
} else {
// 除了数组和对象之外的类型
res = obj;
}
return res;
}
验证:
let obj = {
a: {
name: '小明'
},
b: 111,
c: [1,2,3,4],
d: '你好',
e: null,
f: function() {}
};
let b = deepClone(obj);
obj.a.name = 222;
console.log(obj,b);