【JavaScript】浅拷贝与深拷贝

对象浅拷贝与深拷贝是我们经常在项目开发中遇到的问题。那怎么更好的实现呢?

在JavaScript中,浅拷贝(shallow copy)和深拷贝(deep copy)是处理对象和数组拷贝时经常遇到的概念。它们主要区别在于拷贝的深度和对原始对象内部嵌套对象的处理方式。

浅拷贝(Shallow Copy)

浅拷贝是指只复制对象或数组本身及其直接属性或元素,而不复制其内部的嵌套对象或数组。在浅拷贝中,如果原始对象含有引用类型(如对象、数组等)作为属性值,那么拷贝后的对象也会共享这些引用类型的引用。

在JavaScript中,常见的浅拷贝方法包括:

1、Object.assign():

ini 复制代码
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);

这种方式会复制obj的直接属性到一个新的空对象中,但是对于嵌套对象b,只是复制了其引用,因此shallowCopy.b和obj.b指向同一个对象。

2、扩展操作符(Spread Operator):

ini 复制代码
const shallowCopy = { ...obj };

与Object.assign类似,也是进行浅拷贝。

3、Array.prototype.slice():

对于数组,slice方法可以实现浅拷贝,类似于使用扩展操作符。

深拷贝(Deep Copy)

深拷贝指的是创建一个对象的副本,使得副本的所有层次的属性都是独立于原始对象的。这意味着不仅仅是顶层属性被复制,嵌套的对象、数组、和其他引用类型的属性也被递归地复制到新的实例中。

这与浅拷贝相对,浅拷贝只复制对象的顶层属性,如果属性值是引用类型,则复制的是引用,而不是实际的值。

在JavaScript中,实现深拷贝需要考虑到递归地复制所有嵌套对象或数组。一种常见的深拷贝方法是使用递归和JSON对象的序列化与反序列化:

1、JSON.parse与JSON.stringify

ini 复制代码
function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

const obj = { a: 1, b: { c: 2 } };
const deepCopiedObj = deepCopy(obj);

但是需要注意,使用JSON方法进行深拷贝有一些限制,比如无法处理函数、日期函数、正则表达式、undefined、symbol等特殊对象,循环引用也会导致这种方法失败。

2、实现深拷贝

1、深拷贝 基础版本

javascript 复制代码
        // 深拷贝 基础版本
        function deepClone(target) {
            // 先判断是否为一个对象,如果是,就进行对象的处理流程
            if (typeof target === 'object') {
                let cloneTarget = {};
                // 对属性进行循环遍历
                for (const key in target) {
                    // 递归调用
                    cloneTarget[key] = deepClone(target[key])
                }
                return cloneTarget
            } else {
                return target
            }
        }

2、深拷贝 优化版本

javascript 复制代码
        // 深拷贝 优化版本
        function deepClone2(obj, hash = new WeakMap()) {
            if (obj === null) return null;
            if (typeof obj !== "object") return obj;
            if (obj instanceof Date) return new Date(obj);
            if (obj instanceof RegExp) return new RegExp(obj);
            // 检查哈希表中是否存在拷贝过的对象,处理循环引用
            if (hash.has(obj)) return hash.get(obj);

            let cloneObj = new obj.constructor();
            hash.set(obj, cloneObj);

            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    cloneObj[key] = deepClone(obj[key], hash)
                }
            }
            return cloneObj;
        }

3、深拷贝 最终版本

javascript 复制代码
        // 深拷贝 最终版本
        /**
         * 
         * @param {被克隆的对象} obj
         * @param {避免循环引用} hash
         * */
        function deepClone3(obj, hash = new WeakMap()) {
            // 处理边界值
            // null undefined 和非对象的情况
            if (object === null || typeof obj !== 'object') {
                return obj
            }
            // 对日期的克隆
            if (obj instanceof Date) {
                return new Date(obj)
            }
            // 对正则的克隆
            if (obj instanceof RegExp) {
                return new RegExp(obj)
            }
            // 避免循环引用
            if (hash.has(obj)) {
                return hash.get(obj)
            }
            // 获取属性值 通过Object.getOwnPropertyDescriptors是能够获取symbol等属性值的。
            let allDes = Object.getOwnPropertyDescriptors(obj);
            // 创建一个新对象,并且继承传入对象的原型链
            let cloneObj = Object.create(Object.getPrototypeOf(obj), allDes)

            // 处理循环引用
            hash.set(obj, cloneObj)
            // 使用递归处理,递归克隆每个键对应的值
            for (let key of Reflect.ownKeys(obj)) {
                cloneObj[key] = deepClone(obj[key], hash)
            }
            return cloneObj
        }
相关推荐
QQ1__8115175156 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态6 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子6 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室6 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI6 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing6 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者6 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册6 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李6 小时前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢6 小时前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web