【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
        }
相关推荐
不是吧这都有重名12 分钟前
利用systemd启动部署在服务器上的web应用
运维·服务器·前端
霸王蟹12 分钟前
React中巧妙使用异步组件Suspense优化页面性能。
前端·笔记·学习·react.js·前端框架
Maỿbe21 分钟前
利用html制作简历网页和求职信息网页
前端·html
编程、小哥哥23 分钟前
Java大厂面试:从Web框架到微服务技术的场景化提问与解析
java·spring boot·微服务·面试·技术栈·数据库设计·分布式系统
森叶41 分钟前
Electron 主进程中使用Worker来创建不同间隔的定时器实现过程
前端·javascript·electron
霸王蟹1 小时前
React 19 中的useRef得到了进一步加强。
前端·javascript·笔记·学习·react.js·ts
霸王蟹1 小时前
React 19版本refs也支持清理函数了。
前端·javascript·笔记·react.js·前端框架·ts
繁依Fanyi1 小时前
ColorAid —— 一个面向设计师的色盲模拟工具开发记
开发语言·前端·vue.js·编辑器·codebuddy首席试玩官
codelxy1 小时前
vue引用cesium,解决“Not allowed to load local resource”报错
javascript·vue.js
程序猿阿伟2 小时前
《社交应用动态表情:RN与Flutter实战解码》
javascript·flutter·react native