JavaScript 深拷贝方法总结
前情提要
最近在调uni-app时,经常遇到需要深拷贝对象的情况,今天正好有空,给大家博主用到的深拷贝的方法。
最常用的序列化方法
这个是博主最常用的方法,也是个人认为最简洁方便的的,唯一的确定就是部分特殊类型会拷贝失效,总结如下
优点: 简单快捷,兼容性好
缺点: 无法处理 undefined、function、Symbol 类型、Date 对象(转为 ISO 字符串)、正则表达式(转为空对象)
<html>
<style></style>
<body></body>
<script>
const obj = { a:undefined, b:{b1:1}, c:'测试', d:new Date(), f:function(){} };
const newObj = JSON.parse(JSON.stringify(obj));
// 输出 {b:{b1: 1}, c:"测试", d:"2025-04-11T09:16:12.039Z"}
console.log(newObj)
</script>
</html>
原生方法structuredClone
该方法是HTML5新推出,相比序列化方法,支持了更多数据类型,且更简便了,但是兼容性较差,总结如下
优点: 浏览器原生方法,支持更多数据类型(undefined、Date 对象等)
缺点: 不支持函数、DOM 节点等,且对兼容性有要求,需较新浏览器
<html>
<style></style>
<body></body>
<script>
const obj = { a:undefined, b:{b1:1}, c:'测试', d:new Date() };
const newObj = structuredClone(obj);
// 输出 {a:undefined, b:{b1: 1}, c:"测试", d: Fri Apr 11 2025 17:19:31 GMT+0800 (中国标准时间)}
console.log(newObj)
</script>
</html>
MessageChannel 异步拷贝
该方法是通过信道通信间的传输,来实现对象的深度拷贝,能处理大部分数据类型,唯一的缺点就是需要异步操作
优点: 能处理除了函数外的大部分数据类型
缺点: 需要异步操作,会增加代码的复杂性
<html>
<style></style>
<body></body>
<script>
const obj = { a:undefined, b:{b1:1}, c:'测试', d:new Date() };
function deepClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel()
port2.onmessage = ev => resolve(ev.data)
port1.postMessage(obj)
})
}
deepClone(obj).then(newObj=>{
// 输出 {a:undefined, b:{b1: 1}, c:"测试", d: Fri Apr 11 2025 17:19:31 GMT+0800 (中国标准时间)}
console.log(newObj)
})
</script>
</html>
自定义方法
最后一种就是我们自己写的方法了,具体总结如下
优点: 可自定义处理特殊类型
缺点: 需要手动处理各种数据类型(Date/RegExp/Map/Set等),性能较差(大数据量时)
<html>
<style></style>
<body></body>
<script>
const obj = { a:undefined, b:{b1:1}, c:'测试', d:new Date() };
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj
if (map.has(obj)) return map.get(obj)
let clone = Array.isArray(obj) ? [] : {}
map.set(obj, clone)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], map)
}
}
return clone
}
const newObj = deepClone(obj);
// 输出 {a:undefined, b:{b1: 1}, c:"测试", d: Fri Apr 11 2025 17:19:31 GMT+0800 (中国标准时间)}
console.log(newObj)
</script>
</html>
总结
博主能力有限,基本就只能总结这四种了,大家也可以选择第三方库去实现对象之间的深拷贝,或者有什么其他方法都可评论讨论。