其实一般来说,我们遇到深浅拷贝的问题,都是针对引用数据类型的变量操作.先了解下数据类型
值类型:直接存储其值,在内存中,是存在栈内存中
引用类型: 存储对值的引用,在内存中,是存在堆内存中,变量本身仅仅是一个指向堆中的实际数据地址,存在栈内存中(说白了,就是引用数据类型,实际上存在堆内存中,杂乱无序的放着,但是会有一个指针,指向堆内存中的地址, 而这个指针则是在栈内存中存储)
浅拷贝拷贝的是对象的指针,没有新建空间地址,新老对象共用的同一份地址,指向对内存中同一个地方,修改原来的对象会影响新对象
var obj1={
a:1
}
var obj2=obj1;
obj2.a=5;
console.log('obj1.a',obj1.a); //5
console.log('obj2.a',obj2.a); //5
上述代码,就是一个浅拷贝,对象通过等于号直接赋值,是一个浅拷贝,obj1对象赋值给了obj2,实际上obj2只是拷贝了obj1在内存中栈中的一个地址,也就是指针,他们俩会共同指向堆中数据
深拷贝会在内存中,开辟一个相同的空间地址,并且复制相同的数值,两者互不干扰
用JSON.stringify把对象转为字符串,再用JSON.parse把字符串转为新的对象.
var obj3 = {
classId: 2001,
userinfo: {
name: 'liuqiao',
age: '27'
}
}
var obj4 = JSON.parse(JSON.stringify(obj3));
obj4.userinfo.name='zhangsan';
console.log(obj3.userinfo.name); //liuqiao
console.log(obj4.userinfo.name); //zhangsan
局限性:Number,String,Boolean,Array,可以转为JSON对象,但是function这种不行
lodash是一个高性能的 JavaScript 实用工具库,里面的lodash.cloneDeep()实现深拷贝,原理也是递归实现的
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<script>
var obj3 = {
classId: 2001,
userinfo: {
name: 'liuqiao',
age: '27'
}
}
var obj4 = _.cloneDeep(obj3);
obj4.userinfo.name = 'zhangsan';
console.log(obj3.userinfo.name); //liuqiao
console.log(obj4.userinfo.name); //zhangsan
</script>
实现原理就是通过递归,循环遍历从最顶级开始,去找下一级,直到最后一层位置,然后赋值
function deepClone(source) {
// 判断复制的目标是数组还是对象
const targetObj = source.constructor === Array ? [] : {};
for (let keys in source) { // 遍历目标
if (source.hasOwnProperty(keys)) {
// 如果值是对象,就递归一下
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
} else {
// 如果不是,就直接赋值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
var obj3 = {
classId: 2001,
userinfo: {
name: 'liuqiao',
age: '27'
}
}
var obj4 = deepClone(obj3);
obj4.userinfo.name = 'zhangsan';
console.log(obj3.userinfo.name); //liuqiao
console.log(obj4.userinfo.name); //zhangsan
实际上Object.assign是一个浅拷贝,但是如果是数据结构只有一层,可以实现深拷贝
var obj6={};
var obj5={
a:1
}
obj6= Object.assign(obj6,obj3);
obj6.a=2;
console.log(obj6.a); //2
console.log(obj5.a); //1
Object.assign,如果数据结构有多层,则是浅拷贝
var obj3 = {
classId: 2001,
userinfo: {
name: 'liuqiao',
age: '27'
}
}
var obj4={};
obj4= Object.assign({},obj3);
obj4.userinfo.name = 'zhangsan';
console.log(obj3.userinfo.name); //zhangsan
console.log(obj4.userinfo.name); //zhangsan
与Object.assign() 一样,如果数据结构只有一层,是深拷贝,多层结构了是浅拷贝,只能拷贝第一层的
扩展运算符浅拷贝
var obj3 = {
classId: 2001,
userinfo: {
name: 'liuqiao',
age: '27'
}
}
obj4 = { ...obj3 }
obj4.userinfo.name = 'zhangsan';
obj4.classId=3004;
console.log(obj3.userinfo.name); //zhangsan
console.log(obj4.userinfo.name); //zhangsan
console.log(obj3.classId); //2001
console.log(obj4.classId); //3004
扩展运算符深拷贝
var obj6 = {};
var obj5 = {
a: 1
}
obj6 = { ...obj5 };
obj6.a = 2;
console.log(obj6.a); //2
console.log(obj5.a); //1
实际项目中,根据不同的业务场景,判断是否需要使用深拷贝,方式有很多种,根据需求来自己实现即可!