js中的浅拷贝与深拷贝

article/2025/10/12 8:38:23

在前端开发中的过程中我们经常要接触到浅拷贝与深拷贝的问题,
下面就对浅拷贝与深拷贝的概念区别以及其有哪种实现方法来做一个简单的说明。

概念

浅拷贝:

浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是原始数据类型,拷贝的就是原始数据类型的值,如果是引用数据类型,拷贝的就是内存地址。如果其中一个对象的引用内存地址发生改变,另一个对象也会发生变化。

深拷贝:

深拷贝相对浅拷贝而言,如果遇到属性值为引用类型的时候,它会在堆内存空间中创建一个新的实体对象,新的实体对象内容与被拷贝对象的实体对象内容相同,然后新拷贝出来的对象在栈内存中的对象指针就会指向这个新的实体对象,因此拷贝前后的两个对象指向的是两个内存地址不同但内容相同的实体对象。深拷贝对于一些对象可以使用 JSON 的两个函数来实现,但是由于 JSON 的对象格式比 js 的对象格式更加严格,所以如果属性值里边出现函数或者 Symbol 类型的值时,会转换失败。
在这里插入图片描述图中obj2是深拷贝obj1得出的对象,两者指向的不是同一个实体对象,obj2指向的是一个在堆内存中新创建的实体对象,并且这个实体对象的内容与原本obj1对象指向的实体对象内容相同。

区别

在拷贝原始数据类型的时候其实是不区分深拷贝与浅拷贝的,因为都是拷贝原始数据类型的值。当拷贝的是引用数据类型的时候,则区分浅拷贝、深拷贝,因为浅拷贝只复制引用数据类型的第一层属性、深拷贝可以对引用数据类型的属性进行递归复制

实现方法

浅拷贝的实现方法:

1、Object.assign()

Object.assign()是ES6中对象的拷贝方法,接受的第一个参数是目标对象,其余参数是源对象,用法:Object.assign(target, source_1, ···),该方法可以实现浅拷贝,也可以实现一维对象的深拷贝。

该方法需要注意的是:

  • 如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性。
  • 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回。
  • 因为null 和 undefined 不能转化为对象,所以第一个参数不能为null或 undefined,会报错。
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);  
console.log(target);  // {a: 1, b: 2, c: 3}

2、扩展运算符

使用扩展运算符可以在对对象或数组的第二层开始的拷贝是浅拷贝。

let obj1 = {a:1,b:{c:1}}
let obj2 = {...obj1};
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj1.b.c = 2;
console.log(obj1); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}

3、数组方法实现数组浅拷贝

(1)Array.prototype.slice (单层深拷贝,多层浅拷贝)

slice()方法是JavaScript数组的一个方法,这个方法可以从已有数组中返回选定的元素:用法:array.slice(start, end),该方法不会改变原始数组。
该方法有两个参数,两个参数都可选,如果两个参数都不写,就可以实现一个数组的浅拷贝。

let arr = [1,2,3,4];
console.log(arr.slice()); // [1,2,3,4]
console.log(arr.slice() === arr); //false

(2)Array.prototype.concat (单层深拷贝,多层浅拷贝)

concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。该方法有两个参数,两个参数都可选,如果两个参数都不写,就可以实现一个数组的浅拷贝。

let arr = [1,2,3,4];
console.log(arr.concat()); // [1,2,3,4]
console.log(arr.concat() === arr); //false

4、实现浅拷贝函数

// 浅拷贝的实现;function shallowCopy(object) {// 只拷贝对象if (!object || typeof object !== "object") return;// 根据 object 的类型判断是新建一个数组还是对象let newObject = Array.isArray(object) ? [] : {};// 遍历 object,并且判断是 object 的属性才拷贝for (let key in object) {if (object.hasOwnProperty(key)) {newObject[key] = object[key];}}return newObject;
}

深拷贝的实现方法:

1、JSON.stringify()

JSON.parse(JSON.stringify(obj))是目前比较常用的深拷贝方法之一,它的原理就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象。
这个方法可以简单粗暴的实现深拷贝,但是还存在问题,拷贝的对象中如果有函数,undefined,symbol,当使用过JSON.stringify()进行处理之后,都会消失。

let obj1 = {  a: 0,b: {c: 0}};
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.a = 1;
obj1.b.c = 1;
console.log(obj1); // {a: 1, b: {c: 1}}
console.log(obj2); // {a: 0, b: {c: 0}}

2、函数库lodash的_.cloneDeep方法

该函数库也有提供_.cloneDeep用来做 Deep Copy

var _ = require('lodash');
var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false

3、扩展运算符
使用扩展运算符可以在对对象或数组的第一层的拷贝是深拷贝。

let obj1 = {a:1,b:{c:1}}
let obj2 = {...obj1};
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj1.b.c = 2;
console.log(obj1); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}

4、实现深拷贝函数(解决循环引用)

// 深拷贝的实现
function deepCopy(obj, map) {//判断是否是第一次调用deepCopy方法,是的话创建一个weakmap实例来装遍历过程中出现过的对象if(!map){map = new WeakMap()}//判断传入的obj是否为对象if( obj === null || typeof obj !== 'Object' ){return obj}//如果map中已经存在这个对象说明出现了循环引用问题if(map.get(obj)){return obj}//map中没有就往map中存入该对象map.set(obj,obj)//根据obj的类型来给newObj创建初始值let newObj = Array.isArray(obj) ? [] : {}//遍历objfor(let i in obj){if(obj.hasOwnProperty(i)){ //判断当前属性是否为obj自身的属性if(typeof obj[i] === 'Object'){ //判断当前属性是否为对象类型newObj[i] = deepCopy(obj[i],map) //如果是对象类型就使用该方法进行递归处理}else{newObj[i] = obj[i] //不是对象类型就直接拷贝}}}return newObj //返回拷贝完成的newObj
}

http://chatgpt.dhexx.cn/article/EH29Z0a0.shtml

相关文章

JS之深拷贝与浅拷贝

一、理解 深拷贝 与 浅拷贝 针对于 引用类型(Object,Array,Function) 来说的 浅拷贝:在栈中分配一块新内存,拷贝需要拷贝的值, 对简单数据类型,就是拷贝值;对复杂数据类型,就是拷贝了一份栈内存储的堆内存…

lua踩坑之浅拷贝与深拷贝

文章目录 一、前言二、浅拷贝和深拷贝三、浅拷贝1.拷贝对象为string、number、boolean等基础类型时2.拷贝对象的类型为table类型时 三、深拷贝 一、前言 先来说说,为什么突然谈及到浅拷贝和深拷贝这个问题。因为时间紧任务重,lua零基础参与项目研发&…

解决浅拷贝的五种方式

浅拷贝和深拷贝以及值类型、引用类型概念理解请移步 认识javascript值类型,引用类型及浅拷贝与深拷贝的关系小白gis每周更新与WebGIS设计相关的文章教程,通过在线示例以及demo的方式,介绍Arcgis API、开源gis API的使用方法,帮助学…

iOS-深拷贝和浅拷贝

一、深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 1、深拷贝(Deep Copy):内容拷贝,拷贝数据到一块新内存区域,指针指向拷贝的数据区 (另外创造一个一模一样的对象,新对象跟原对象不共享内存&am…

实现浅拷贝

浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值,如果是引用数据类型,拷贝的就是内存地址。如果其中一个对象的引用内存地址发生改变,另一…

浅拷贝

图片转自js 深拷贝 vs 浅拷贝 我们平常说的深拷贝和浅拷贝都是基于对诸如 Object 和 Array 等引用数据类型的拷贝。对于基本数据而言,拷贝为某个值的赋值。 在说拷贝之前,我们先复习一下什么是基本数据类型和引用类型。 基本数据类型 JavaScript 中基…

深浅拷贝以及解决浅拷贝(以string浅拷贝为例)

一、什么是浅拷贝 在类和对象的时候,其中编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅…

ctf之培根密码

根据特征怀疑是培根密码 flag{AAAABAAAAAAAABAABBBAABBABABAAABAABAAAABBAABAAABABBABAAAAAABAABAAAABBBABABAABAABA} 直接在线解密 https://tool.bugku.com/peigen/ flag{BACONISDELICIOUS}

培根密码加解密

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴! 0x00 介绍 培根密码实际上就是一种替换密…

培根密码解密脚本

官方吐槽:疫情复发难受,什么时候是个头 #!/usr/bin/env python3 # -*- coding:utf-8 -*- #Author:later_future import string miweninput("请输入密文:") count0 msg"" flag"" #培根加密百度百科…

攻防世界crypto部分sherlock的writeup,原来不是培根密码。

下载附件后,发现是一个很大的文本,搜了下flag没啥收获。 1、后来看到下面这个 2、明显的故意大写,难道是培根密码?这就有思路了,将大写过滤出来: cat f590c0f99c014b01a5ab8b611b46c57c.txt | grep -Eo […

培根密码加解密(Python)

原理 加密时,明文中的每个字母会根据下面转换成5个字母; 解密时,密文中的每5个字母为一组转换成对应的1个字母; Python代码如下: CODE_TABLE { #培根字典aaaaa:a,aaaab:b,aaaba:c,aaabb:d,aabaa:e,aabab:f,aabba:…

CTF密码学-加解密总结

零基础学黑客,搜索公众号:白帽子左一密码学基本简介 密码学(在西欧语文中,源于希腊语krypts“隐藏的”,和grphein“书写”)是研究如何隐密地传递信息的学科。 在现代特别指对信息以及其传输的数学性研究&…

密码及编码

1. 密码 古典密码学 凯撒密码(Caeser):位移密码 特殊形式(加解密相同,因为26个字母是循环的):ROT13 栅栏密码:分组密码。 弗吉尼亚 现代密码学 对称加密算法:使用加密用过的秘钥及相同算法的…

CTF-密码学-培根密码

题目:bacon bAcon iS a MEaT prodUcT prePared frOm a pig and UsuALLy cUReD. 读题:翻译过来意思是培根 审题:联想到培根密码 解题:培根密码就是大写变A小写变B import string timu"bAcon iS a MEaT prodUcT prePared frOm…

【无标题】简单的培根密码解密

第一题 题目AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAAAABB 此题由大写字母AB组成,不难看出这可以用培根密码转换器进行解密得出flag 解密得出flag{HELLO WORD}

CTF-Show密码学【摩斯码、培根密码】

萌新 密码33 一、题目信息 题目名称:我想吃培根题目描述:-- — .-. … . …–.- … … …–.- -.-. — — .-… …–.- -… …- - …–.- -… .- -.-. — -. …–.- … … …–.- -.-. — — .-… . .-. …–.- – – -… -… – -… – -… – – – -…

CTF-培根密码

CTF学习上的一些疑点和解疑 主题:培根密码的随意性 反正我是觉得挺离谱的 序章 CTF学习上的一些疑点和解疑前言:培根小贴士一、培根密码是什么?二、解答1.题目2.解密顺序 总结还没听懂的我给大家展现一些例子: 前言:…

密码学笔记——培根密码

培根密码,培根所用的密码是一种本质上用二进制数设计的,没有用通常的0和1来表示,而是采用a和b 一、培根密码加密方式 第一种方式: A aaaaa B aaaab C aaaba D aaabb E aabaa F aabab G aabba H aabbb I abaaa J abaab K ababa L ababb M abbaa N abbab O abbba P abb…

培根密码(Bacon)——python解密

简介 培根密码,又名倍康尼密码(英语:Bacon’s cipher)是由法兰西斯培根发明的一种隐写术。 特点: 培根密码本质上是将二进制信息通过样式的区别,加在了正常书写之上。培根密码所包含的信息可以和用于承载…