深拷贝与浅拷贝:理解并避免潜在问题

一、引言

在JavaScript中,我们经常需要复制对象或数组。然而,我们可能并不完全理解这两种不同的复制方式:深拷贝和浅拷贝。在本文中,我们将深入探讨这两种复制方式,以及它们在编程中的应用和潜在问题。

二、浅拷贝

浅拷贝(Shallow Copy)是指只复制对象的顶层属性。如果对象的属性是一个引用类型(例如,数组或对象),那么这两个对象将共享这个引用。这意味着,如果你更改了其中一个对象的属性,另一个对象的属性也会被改变。

在JavaScript中,你可以使用Object.assign()方法或Object.create()方法来实现浅拷贝。例如:

js 复制代码
let original = {a: 1, b: 2, c: {d: 3}};  
let copy = Object.assign({}, original);

或者使用JavaScript原生模式,通过封装一个方法实现。例如:

js 复制代码
function clone (original,taraget){
    const tar = taraget || {}; // taraget 可能不会传入,所以在这里判断一下
    for(const key in original){
        // 使用objetc.hasOwnProperty()方法,获取original自身的属性,防止获取到原型的属性
        if(original.hasOwnProperty(key)){
            taraget[key] = original[key];
        }
    }
    return tar;
}

三、深拷贝

深拷贝(Deep Copy)是指不仅复制对象的顶层属性,而且复制其所有嵌套的属性。如果对象的属性是一个引用类型,那么这两个对象将拥有各自独立的副本。这样,你可以自由地修改其中一个对象,而不会影响到另一个对象。

在JavaScript中,你可以使用JSON的parse()和stringify()方法来实现深拷贝。例如:

js 复制代码
let original = {a: 1, b: 2, c: {d: 3}};  
let copy = JSON.parse(JSON.stringify(original));
// 此方法虽然可以实现深拷贝,但是不建议这样做,如果属性中存在Function Reg Date等,会出现问题,拷贝之后会访问不到

所以通常情况下我们提供封装一个方法去实现。例如:

js 复制代码
function deepClone (orginal,target){
    const tar = target || {};
    const toStr = Object.prototype.toString; // 这里其实是调用Object.prototype.toString.call()方法
    const arrType = '[object Array]';
    for (const key in orginal){
        if(orginal.hasOwnProperty(key)){
            // 判断当前属性是否为引用类型  因为null 的类型返回为object 所以 属性为null 的 我们排除
            if(typeof(orginal[key]) === 'object' && orginal[key] !== null){
                // 若果当前属性为引用类型 我们在判断是否是数组类型
                // 当前只判断了数组和对象,Function,Date,等内置的对象 可自行增加判断
                if(toStr.call(orginal[key]) === arrType) {
                    tar[key] = [];
                }else {
                    tar[key] = {};
                }deepClone (orginal[key],tar[key]);
            }else {
                tar[key] = orginal[key];
            }
        }
    }
    return tar;
}

四、潜在问题

在使用浅拷贝时,如果原对象中的某个引用类型属性被修改,那么所有使用这个属性的对象都会受到影响。这可能会导致意料之外的结果,甚至可能导致程序错误。(具体问题是堆内存和栈内存的存值问题本文暂不解释)

js 复制代码
let original = {a: 1, b: 2, c: {d: 3}};  
let copy = Object.assign({}, original);  
copy.c.d = 4; // 这里修改了copy对象的属性,但实际上也修改了original对象的属性  
console.log(original.c.d); // 输出4,而不是3

五、结论

深拷贝和浅拷贝是编程中常见的概念,理解并正确使用它们对于避免潜在问题非常重要。当需要复制对象时,你需要考虑是否需要复制对象的所有嵌套属性。如果需要,你应该使用深拷贝;如果不需要,你可以使用浅拷贝。

相关推荐
疯狂SQL1 小时前
JWT 在线解码、验签、生成一篇讲透:附前端实现、工具架构与在线体验地址
javascript·jwt·编解码·jwt测试
前端一小卒1 小时前
不手写代码的第 30 天,我才明白前端这个岗位还剩什么
前端·javascript·ai编程
Ajie'Blog1 小时前
Copilot Agent Tasks API 开放:AI 编程开始进入后台任务时代
服务器·前端·javascript·人工智能·copilot·ai编程
老毛肚2 小时前
jeecgboot vue TS & 模板化 04
前端·javascript·vue.js
晓13132 小时前
【Cocos Creator 2.x】篇——第二章 入门
javascript·游戏引擎
Electrolux4 小时前
[onlyoffice-v9]纯前端怎么实现编辑预览office
前端·javascript·github
VidDown4 小时前
Webhook 调试器:让第三方回调“原形毕露”
java·开发语言·javascript·编辑器·postman
kyriewen4 小时前
我读了一遍 Babel 编译后的 async/await,终于搞懂了它的原理(附 20 行手写实现)
前端·javascript·面试
半岛@少年6 小时前
都是JS,CJS和ESM有什么区别?
javascript·esm·前端模块化·cjs
想吃火锅10056 小时前
【leetcode】165.比较版本号js
javascript·算法·leetcode