一文解读深浅拷贝的理解和几种使用方法

深拷贝和浅拷贝是面试中经常被问到了,理解其原理和深浅拷贝差异以及多种深浅拷贝方法才能熟练在实际项目中使用做到游刃有余。本文将从作用原理到具体代码实现和多种使用方法进行展开解读。

深浅拷贝的理解

浅拷贝

浅拷贝从字面意义上就是浅层的拷贝对象,不涉及到深层次的拷贝,也就是说只复制对象表层数据,只是为原来的对象创建新的内存,但是嵌套的引用类型(如:数组、子对象)仍然需要与原对象共享内存,修改副本的嵌套字段会同步影响原对象,进而产生污染。

其核心就是,由于JS的数据类型的存储机制,基本类型(字符串、数字等)直接存在 内存中,复杂类型(对象、数组等)在栈中只存堆内存的地址引用,而堆内存才存实际的数据。浅拷贝时,只是复制栈内存而不对堆内存进行复制。 如图:

极简代码理解就是:

js 复制代码
// 原始对象
const userInfo = { 
    name: "张三", // 基本类型(直接存在栈内存里) 
    address: { city: "北京" } // 复杂数据类型(地址引用在栈,实际数据在堆) 
    };
// 浅拷贝:创建新对象
const formData = { ...userInfo }; 
// 1. 对比新对象本身的地址
console.log(userInfo === formData); // false,说明地址不同,是新的内存
// 2. 对比嵌套address的地址
console.log(userInfo.address === formData.address); // true,相同,说明内存共享,指向的是同一个地址
// 3. 修改嵌套字段,验证污染 
formData.address.city = "上海"; 
console.log(userInfo.address.city); // 输出"上海",说明原对象被污染了

深拷贝

理解了浅拷贝,深拷贝就是完全复制原始对象及所有的嵌套数据 ,会为原对象和所有嵌套的引用类型(如数组、子对象)创建独立的内存空间,副本与原对象彻底隔离,修改副本不会影响到原对象

深浅拷贝的方法

浅拷贝的5种常用方法

1. 对象展开运算符{...obj},最简洁的实现方式,适用于普通对象

js 复制代码
const shallowCopy = { ...userInfo };

2.数组展开运算符,数组专属浅拷贝

js 复制代码
const shallowCopy = { ...originArr };

3.Object.assign(target,source),可以合并多个对象,仅浅拷贝源对象表层

js 复制代码
const shallowCopy = Object.assign({},userInfo1,userInfo2,userInfo3,....);

4.数组slice(),数组截取(不传参时等价于浅拷贝)

js 复制代码
const shallowCopy = originalArr.slice();

5.数组concat(),拼接空数组实现浅拷贝

js 复制代码
const shallowArr = originalArr.concat([]);

深拷贝的4种常用方法

1.JSON.parse(JSON.stringify(obj)),最常用(局限性:不支持函数、Symbol、Date、RegExp)

js 复制代码
const deepCopy = JSON.parse(JSON.stringify(userInfo));

2.递归遍历拷贝, 自定义实现(灵活处理所有类型,需手写逻辑),面试手写题常考

js 复制代码
function deepClone(obj){
    // 类型判断 
    if(obj isntanceof Date) return new Date(obj);
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Error) return new Error(obj.message);
    if(obj instanceof Function) return function(...args){
        return obj.call(this,...args);
    };
    if( obj === null || typeof obj !== 'object') return obj;
    
    const newObj = Array.isArray(obj) ? [] : {};
    
    for(let key in obj){
        if(Object.hasOwn(obj,key)){
            if(typeof obj[key] === "object"){
                newObj[key] = deepClone(obj[key]); // 递归拷贝嵌套层
            }
            else{
                newObj[key] = obj[key]
            }
        }
         
    }
    return newObj;
}

3.第三方库, 稳定可靠(开发首选)

  • Lodash中的 _.cloneDeep(obj)(支持所有类型,处理循环引用)
  • jQuery中的 $.extend(true,{},obj)(第一个参数为true表示深拷贝)

4.structuredClone(), 浏览器原生API,支持循环引用、Date/RegExp,但不支持函数

相关推荐
全栈前端老曹2 小时前
【包管理】npm init 项目名后底层发生了什么的完整逻辑
前端·javascript·npm·node.js·json·包管理·底层原理
HHHHHY2 小时前
mathjs简单实现一个数学计算公式及校验组件
前端·javascript·vue.js
boooooooom2 小时前
Vue3 provide/inject 跨层级通信:最佳实践与避坑指南
前端·vue.js
一颗烂土豆2 小时前
Vue 3 + Three.js 打造轻量级 3D 图表库 —— chart3
前端·vue.js·数据可视化
青莲8433 小时前
Android 动画机制完整详解
android·前端·面试
iReachers3 小时前
HTML打包APK(安卓APP)中下载功能常见问题和详细介绍
前端·javascript·html·html打包apk·网页打包app·下载功能
颜酱3 小时前
前端算法必备:双指针从入门到很熟练(快慢指针+相向指针+滑动窗口)
前端·后端·算法
lichenyang4533 小时前
从零开始:使用 Docker 部署 React 前端项目完整实战
前端
明月_清风3 小时前
【开源项目推荐】Biome:让前端代码质量工具链快到飞起来
前端
愈努力俞幸运3 小时前
vue3 demo教程(Vue Devtools)
前端·javascript·vue.js