JS - 浅拷贝和深拷贝
2023-12-15 04:53:40
目录
1,概念
浅拷贝:只拷贝基本类型的数据,引用类型的数据拷贝后也会发生引用,因为拷贝的是对象的引用地址。
深拷贝:在堆中重新分配内存,并把源对象中所有属性都新建拷贝,新旧对象完全隔离,互不影响。
2,浅拷贝
1,直接赋值
const user = {
name: '下雪天的夏风'
}
const user2 = user
user.name = 'xxx'
console.log(user); // { name: 'xxx' }
console.log(user2); // { name: 'xxx' }
console.log(user === user2); // true
2,Object.assign()
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = Object.assign({}, user);
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
3,扩展运算符
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = { ...user };
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
4,数组 slice() 和 concat()
数组元素是引用类型时,同样拷贝的是引用地址。
const arr1 = [1, true, "Hello", { name: "下雪天的夏风", age: 18 }];
// slice() 替换为 concat() 结果一致。
const arr2 = arr1.slice();
arr2[0] = 2;
arr2[3].age = 36;
console.log(arr1); // [ 1, true, 'Hello', { name: '下雪天的夏风', age: 36 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: '下雪天的夏风', age: 36 } ]
5,jquery 中的 $.extend()
在 jQuery 中,$.extend([deep], target, object1, [objectN])
方法可进行深浅拷贝。jquery 中文文档
- deep:
true
为深拷贝,默认为false
浅拷贝 - target:目标对象
- object1:待拷贝到第一个源对象
- objectN:待拷贝到第N个源对象
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = {};
$.extend(user2, user);
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>
6,lodash.clone()
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = _.clone(user);
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>
3,深拷贝
遇到的问题和使用建议后面会介绍。
1,JSON.parse(JSON.stringify)
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = JSON.parse(JSON.stringify(user));
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
2,structuredClone()
全局属性。浏览器环境是 window 的属性,node 环境是 global 的属性。
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = structuredClone(user);
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
3,jquery 中的 $.extend()
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = {};
$.extend(true, user2, user);
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>
4,lodash.cloneDeep()
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
const user = {
name: "下雪天的夏风",
address: {
province: "陕西",
city: "西安",
},
};
const user2 = _.cloneDeep(user);
user2.name = "xxx";
user2.address.province = "北京";
console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>
4,遇到的问题和使用建议
遇到的问题
可以看到,上面的例子中使用的都是简单的基本数据类型和普通对象,这也是日常开发中最常见的。
但还有一些特殊情况,比如函数在进行深拷贝时,其实和基本类型一样直接拷贝即可。但函数不支持序列化和结构化算法!所以 JSON.parse(JSON.stringify)
和 structuredClone()
无法处理函数,所以源对象中有函数时会有问题!
const user = {
getAge() {
console.log(18);
},
};
const user2 = JSON.parse(JSON.stringify(user));
console.log(user2); // {},函数直接被忽略
const user = {
getAge() {
console.log(18);
},
};
// 结构化算法无法处理函数。
// Uncaught DOMException: Failed to execute 'structuredClone' on 'Window': getAge()
const user2 = window.structuredClone(user);
还有一些特殊的对象,比如日期对象,正则对象,包装类型,Map,Set 等,在拷贝时都需要特殊处理。
使用建议
在生成环境中的建议:
- 如果只是简单的数据类型,比如基本类型和普通对象,用哪种方法都无所谓。
- 如果有复杂的类型,建议使用
lodash.cloneDeep()
或$.extend()
。
5,手动递归简单实现深拷贝
特殊的类型就不考虑了,主要是完善下 JSON.parse(JSON.stringify)
不支持函数的拷贝。Map 和 Set 其实也是判断后遍历递归即可。
function deepClone(target) {
let result;
// 基本类型、函数,直接赋值。
if (typeof target !== "object" || typeof target === null) {
result = target;
} else {
result = Array.isArray(target) ? [] : {};
for (const key in target) {
result[key] = deepClone(target[key]);
}
}
return result;
}
以上。
文章来源:https://blog.csdn.net/qq_40147756/article/details/135005693
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!