JavaScript深拷贝与浅拷贝原理及实现方式详解

作者:异步漫步时间:2026-10-25 22:06:30浏览:457

本文深入解析JavaScript中数据在堆栈内存中的存储机制,阐明深拷贝与浅拷贝的本质区别。通过遍历赋值、Object.create()以及JSON序列化三种方式,详细演示如何实现对象的浅拷贝与深拷贝,并分析各方法的适用场景与局限性,帮助开发者正确选择对象复制策略。

一、JS中数据的存储形式-堆栈

首先简要了解堆与栈的概念:

栈(Stack):计算机为原始类型数据分配的一块内存空间,用于存储 string、number 等基本类型。

堆(Heap):计算机为引用类型数据分配的一块内存空间,用于存储 object 等复杂类型。

接下来分别分析以下两段代码的执行结果:

var a = 'jack'
var b = a
b = 'andy'
console.log(a,b);//jack andy
var c = {key : 1}
var d = c
d.key = 2
console.log(c,d);//{ key: 2 } { key: 2 }

阅读后可能会产生一个疑问:第一段代码逻辑清晰,但在第二段代码中,明明修改的是 d 对象的 key,为什么 c 对象中的 key 也随之改变了?

这源于堆与栈的工作原理。定义原始类型数据时,系统会开辟栈空间;声明基本变量时,其值直接存储在栈内存中。复制基本变量时,系统会将栈中的数据完整复制一份到新内存地址,因此两个变量相互独立,互不影响。若对引用类型进行复制,系统仅复制了内存地址引用,原变量与新变量指向同一堆内存地址。因此,修改新变量的属性会直接反映在原变量上。

二、深浅拷贝的三种方式

  • 遍历赋值
  • Object.create()
  • JSON.parse()和JSON.stringify()

深拷贝与浅拷贝的核心区别在于:

假设将对象 A 赋值给对象 B,当修改 A 时,若 B 随之变化,则为浅拷贝;若 B 保持不变,则为深拷贝。

遍历赋值

参考以下代码示例:

var obj = {
  a:'hello',
  b:{
    a:'world',
    b:111
  },
  c:[11,'jack','abdy']
}
function clone(obj) {
  var objnew = {}
  for(var i in obj) {
    objnew[i] = obj[i]
  }
  return objnew
}
var objcopy = clone(obj)
console.log(obj);
console.log(objcopy);

此处定义了一个对象 obj,并编写 clone 方法以实现对象复制。调用该方法后,分别输出原对象与复制后的对象,观察其差异:

一、JS中数据的存储形式-堆栈

控制台输出的两个结果看似完全一致,但它们是否真正相同?

二者存在本质区别。根据浅拷贝定义,若修改 objcopy 导致 obj 发生变化,则确认为浅拷贝。

接下来进行验证,修改 objcopy.b.a 的值,观察 obj 是否随之改变:

一、JS中数据的存储形式-堆栈

将 objcopy.b.a 赋值为字符串 'hhhh' 后,obj.b.a 也变为 'hhhh'。这证实了初始拷贝为浅拷贝。由于 obj.b 是引用类型,objcopy.b 与 obj.b 指向同一内存地址,因此修改 objcopy.b.a 会同步影响 obj.b.a。

Object.create()

该方法仅需一行代码:

var objcopy = Object.create(obj)

使用 Object.create() 复制时,原对象会被复制到新对象的原型链(__proto__)上,而非直接复制到当前对象自身属性中。再次修改 objcopy.b.a 的值,观察 obj 是否发生变化:

一、JS中数据的存储形式-堆栈

因此,这也属于浅拷贝。

遍历赋值实现深拷贝

以下是实现深拷贝的克隆函数:

function deepclone(startobj,endobj) {
  var obj = endobj || {}
  for(var i in startobj)
  {
    if(typeof startobj[i] === 'object') {
      obj[i] = startobj[i].constructor === Array ? [] : {}
      deepclone(startobj[i],obj[i])
    }else {
      obj[i] = startobj[i]
    }
  }
  return obj
}

需注意,在递归调用时,必须将当前处理的 obj[i] 作为参数传入,否则每次递归时 obj 会被重置为空对象,从而影响已克隆的数据结构。

接下来验证该深拷贝是否生效:

var objcopy = deepclone(obj)
objcopy.b.a = 'hhhh'
console.log(obj);
console.log(objcopy);

运行结果如下:

一、JS中数据的存储形式-堆栈

结果表明深拷贝已成功实现。

通过JSON.parse()和JSON.stringify()实现深拷贝

这是开发工作中最常见的实现方式之一。

var objcopy = JSON.parse(JSON.stringify(obj))

首先通过 JSON.stringify 将初始对象转换为字符串,再通过 JSON.parse 将其转回对象类型。

这种方式能实现深拷贝的原因在于:JSON.stringify 将对象转换为字符串后,数据存储于栈内存中,从而避免了地址引用的混淆;随后通过 JSON.parse 重新构建对象类型,实现深层复制。

至此,关于JavaScript深拷贝与浅拷贝原理的深入探究介绍完毕。如需了解更多JS深拷贝与浅拷贝相关内容,请查阅本站过往文章或继续浏览后续内容,感谢大家的支持!

作者最新文章