JavaScript深拷贝原理与三种实现方式详解
本文详细解析JavaScript中值类型与引用类型的内存存储机制,阐明浅拷贝仅复制指针而深拷贝完全克隆数据的区别。文章对比了JSON序列化、扩展运算符及手写递归函数三种深拷贝方案,分析各自在嵌套对象、函数及循环引用上的局限性,并提供完整的递归实现代码示例,帮助开发者根据场景选择最优拷贝策略。
JavaScript深拷贝
在深入探讨深拷贝之前,首先需要理解JavaScript中数据的存储机制。
数据存储方式
理解值类型与引用类型的存储差异是掌握拷贝概念的基础。
JavaScript的数据类型主要分为两大类。
值类型包括:字符串(String)、数字 (Number)、布尔值 (Boolean)、空值(Null)、未定义(Undefined)以及符号(Symbol)。
值类型的数据存储在栈内存中,其数据大小是固定的,内存空间可以明确分配。
引用数据类型主要包括:对象(Object)、数组((Array)以及函数(Function)。
引用类型的数据存储在堆内存中,而栈内存中仅保存指向堆内存地址的指针。程序通过该指针访问堆内存中的实际数据。
存储结构示意图如下:

什么是浅拷贝与深拷贝
明确了存储方式后,接下来讨论浅拷贝和深拷贝的概念。
拷贝(copy)类似于复制粘贴操作,下面通过具体示例进行说明。
当对值类型和引用类型分别进行赋值操作时,表现有所不同。
var a = 5
var b = a
b += 5
console.log('a=' + a,'b=' + b)
var arr=[1,2,3]
var brr=arr
brr.push(10)
console.log("arr为",arr)
console.log("brr为",brr)

现象:值类型的赋值互不影响,但引用类型(如数组)在修改副本时,原数组也会发生变化。
分析:浅拷贝仅针对引用类型,简单赋值仅复制指向堆内存的指针,导致原对象与副本共享同一数据。深拷贝则是完全复制引用类型的数据结构,而非仅仅复制地址指针。
浅拷贝原理示意图如下:

常用的深拷贝实现方法
为了避免修改副本时影响原数据,对引用类型赋值时需采用深拷贝。
1. 使用JSON.stringify和JSON.parse
该方法可深拷贝数组和对象,支持嵌套结构,但无法处理函数。
缺点:无法拷贝对象中的方法(函数)。
使用方法示例:
var brr=JSON.parse(JSON.stringify(arr))
具体代码示例:
var arr = {
name: '浪漫主义码农',
age: 20,
adress: ['jiangxi', 'changsha'],
friends: {
friend1: '张三',
friend2: '李四'
},
function(){
console.log("我是浪漫主义的对象")
}
}
var brr=JSON.parse(JSON.stringify(arr))
brr.name='法外狂徒张三'
brr.adress[0]='长沙'
console.log("arr为", arr)
console.log("brr为", brr)

2. 使用扩展运算符
利用对象的结构赋值特性实现。
缺点:无法对嵌套对象进行深拷贝,仅对第一层引用对象进行拷贝。
使用方法示例:
var brr={...arr}
具体代码示例:
var arr = {
name: '浪漫主义码农',
age: 20,
adress: ['jiangxi', 'changsha'],
friends: {
friend1: '张三',
friend2: '李四'
},
function(){
console.log("我是浪漫主义的对象")
}
}
var brr={...arr}
brr.name='法外狂徒张三'
brr.adress[0]='长沙'
console.log("arr为", arr)
console.log("brr为", brr)

3. 手写递归深拷贝函数
此方法能完美解决上述问题。
函数定义示例:
//使用递归实现深拷贝
function deepClone(obj) {
//判断拷贝的obj是对象还是数组
var objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object") { //obj不能为空,并且是对象或者是数组 因为null也是object
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") { //obj里面属性值不为空并且还是对象,进行深度拷贝
objClone[key] = deepClone(obj[key]); //递归进行深度的拷贝
} else {
objClone[key] = obj[key]; //直接拷贝
}
}
}
}
return objClone;
}
具体调用示例:
var arr = {
name: '浪漫主义码农',
age: 20,
adress: ['jiangxi', 'changsha'],
friends: {
friend1: '张三',
friend2: '李四'
},
fun: function(){
console.log("我是" + this.name + "的对象")
}
}
var brr = deepClone(arr)
brr.name = '法外狂徒张三'
brr.adress[0] = '长沙'
console.log("arr为", arr)
arr.fun()
console.log("brr为", brr)
brr.fun()
//使用递归实现深拷贝
function deepClone(obj) {
//判断拷贝的obj是对象还是数组
var objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object") { //obj不能为空,并且是对象或者是数组 因为null也是object
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") { //obj里面属性值不为空并且还是对象,进行深度拷贝
objClone[key] = deepClone(obj[key]); //递归进行深度的拷贝
} else {
objClone[key] = obj[key]; //直接拷贝
}
}
}
}
return objClone;
}

总结
本文到此结束,希望能为读者提供帮助,欢迎关注本站获取更多技术内容。
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
