深拷贝与浅拷贝的区别

article/2025/9/17 4:04:46

深拷贝与浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是深拷贝(值拷贝)),是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这时,你修改两个中的任意一个都不会影响另一个;而对于对象或引用数据在进行浅拷贝时,只是将对象的引用复制了一份,也就是内存地址,即两个不同的变量指向了同一个内存地址,那么在改变任意一个变量的值都是改变内存地址所存储的值,因此两个变量的值都会改变。

1. js中的深拷贝(值拷贝):

js 中的基本数据类型:String,Number,Boolean,Null,Undefined,在赋值的过程中都是值拷贝。
例如,let a = 10; b = a ,修改其中一个变量的值,不会影响到另一个变量的值。

2. js 中的浅拷贝(引用拷贝)

js 中的对象数据类型:Object,Array,Function,Map,Set,在赋值过程中都是引用拷贝。

let obj = {	name:'静如秋叶',age: 3,height:100
}
let obj2 = obj
obj2.name = '小花';
console.log(obj) // {name:'小花',age: 3,height:100}
console.log(obj2) // {name:'小花',age: 3,height:100}

当修改obj2的name属性时,也会修改obj的name,因为他们指向同一块内存地址。

3. 将浅拷贝转换为深拷贝

在实际的项目开发中,我们在多数情况下不希望将对象进行浅拷贝,因为值会相互影响,容易出错。

3.1 Array的深拷贝

1. 通过slice方法

slice() 操作数组时,不会对原数组有影响,会产出一个新的数组。

let arr1 = [1,42,5,6]
let arr2 = arr1.slice()
arr2[0] = 100
console.log(arr1)  // [1,42,5,6]
console.log(arr2)  // [100,42,5,6] 

数组arr2的改变未引起arr1的变化。

2. 通过concat方法

数组的concat() 方法,能够连接两个数组,同样不会改变原来的数组。
用一个空数组[ ] 连接另一个数组,即可实现深拷贝。

let arr3 = ['cat','dog','pig']
let arr4 = [].concat(arr3)
arr3[2] = 'big pig'
console.log(arr3)   // ['cat','dog','big pig']
console.log(arr4)   // ['cat','dog','pig']

3. 通过ES6语法中的 …

ES6中的 … ,我们经常在数组的深拷贝中用到。

let arr5 = [0,0,1]
let arr6 = [...arr5]
arr5[0] = 10000
console.log(arr5) // [10000,0,1]
console.log(arr6) // [0,0,1]

4. 通过Array.from 方法

Array.from() 方法能从一个类似数组或可迭代对象中返回一个新的数组实例。通过Array.from() 方法能获取到一个数组的深拷贝。

let arr7 = [1,2,3]
let arr8 = Array.from(arr7)
arr7[1] = 1000
console.log(arr7) // [1,1000,3]
console.log(arr8) // [1,2,3]

3.2 Object 的深拷贝

1. 通过Object.assign() 方法

ES6的Object.assign(target,…sources) 用于对象的合并,将源对象的所有可枚举属性,复制到目标对象中,并返回合并后的目标对象。后来的源对象的属性值,将会覆盖它之前的对象的属性。

let person = {name: 'xia',age: 25,height: 160 
}
let otherPerson = Object.assign({},person)
person.age = 30
console.log(person) // {name: "xia", age: 30, height: 160}
console.log(otherPerson) // {name: "xia", age: 25, height: 160}

Object.assign()是ES6中对象的拷贝方法,接受的第一个参数是目标对象,其余参数是源对象。
对于一维对象(数组)是深拷贝,对于多维对象(数组)是浅拷贝.
注意:
1.如果目标对象和源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
2.如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回.
3.因为null和undefined不能转化为对象,所以第一个参数不能为null或undefined,会报错。

4. 万能转换器(对Array和Object)

前面讲了Array和Object的深拷贝方法,但是对于有更深层次的结构关系(数组套数组,数组套对象,对象套对象等),上面的方法就失灵了,可以看下面的例子。

let personArr = [{name: 'xia'}, {name: 'zhang'}]
let otherPersonArr2 = [...personArr]
personArr[0].name = 'xia xia'
console.log(personArr)
console.log(otherPersonArr2)

在这里插入图片描述
万能转换器JSON.parse(JSON.stringify(obj)) 深拷贝已对象,它可以深拷贝多层级的,不同担心嵌套问题。

  • JSON.stringify() 将对象序列化成json对象
  • JSON.parse() 反序列化——将json对象反序列化成js对象

JSON.stringify(obj) 将js中的对象转化为json字符串

let jack = {name: 'jack'
}
console.log(jack)
console.log(JSON.stringify(jack))

它们在格式上有区别。下图中的第一个是对象,name没有双引号括起来。第二个是json字符串,其中,name用双引号括起来了。
在这里插入图片描述
JSON.parse() 将json字符串解析成对象

 let obj = {name: '静茹秋叶'}console.log('obj: ', obj)console.log('json string: ', JSON.stringify(obj))let str = JSON.stringify(obj)console.log('--------------')console.log(str)console.log('str to obj: ', JSON.parse(str))

在这里插入图片描述

5. Vue中的浅拷贝和深拷贝

两个button-counter 共用同一个jack对象,用同一块地址,当其中一个实例改变时,会影响另一个实例的值。(浅拷贝)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>vue的data选项</title><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body><div id="app"><button-counter></button-counter><button-counter></button-counter></div><script>let jack = {counter: 0}// 子组件Vue.component('button-counter', {data() {// 函数类型return jack},template: `<button @click="counter++">click {{counter}} times</button>`})let vm = new Vue({el: '#app' // mount到DOM上})</script>
</body>
</html>

采用深拷贝,重新创建一块内存。这样,vue的button-counter组件中的counter值互不影响。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>vue的data选项</title><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body><div id="app"><button-counter></button-counter><button-counter></button-counter></div><script>let jack = {counter: 0}// 子组件Vue.component('button-counter', {data() {// 函数类型return JSON.parse(JSON.stringify(jack))},template: `<button @click="counter++">click {{counter}} times</button>`})let vm = new Vue({el: '#app' // mount到DOM上})</script>
</body>
</html>

http://chatgpt.dhexx.cn/article/1y5MAqH2.shtml

相关文章

深拷贝和浅拷贝的区别是什么?

深拷贝和浅拷贝的区别是什么? 1、浅拷贝 (1)、定义 被复制对象的所有变量都含有与原来的对象相同的值&#xff0c;而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主"对象进行拷贝&#xff0c;但不会复制主对象里面的对象。"里面的对象”会在…

深拷贝和浅拷贝常见的实现方式

浅拷贝的实现方式 1. Object.assign()方法 assign()方法是把任意多个的源对象自身的可枚举属性拷贝给目标对象&#xff0c;然后返回目标对象。但是他的拷贝方式不是固定的&#xff0c;看下面的代码演示&#xff1a; let obj {username: kobe}; let obj2 Object.assign({},o…

什么是深拷贝和浅拷贝?以及怎么实现深拷贝和浅拷贝?

拷贝浅是创建一个新对象&#xff0c;这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型&#xff0c;拷贝的就是基本类型的值&#xff0c;如果属性是引用类型&#xff0c;拷贝的就是内存地址&#xff0c;所以如果其中一个对象改变了这个地址&#xff0c;就会影响到…

Java的深拷贝与浅拷贝的区别

1.二者的区别 浅拷贝&#xff1a;在拷贝一个对象时&#xff0c;对对象的基本数据类型的成员变量进行拷贝&#xff0c;但对引用类型的成员变量只进行引用的传递&#xff0c;并没有创建一个新的对象&#xff0c;当对引用类型的内容修改会影响被拷贝的对象。 深拷贝&#xff1a;在…

深拷贝和浅拷贝的区别(必须掌握)

前言&#xff1a; 在面试中&#xff0c;你必须要知道的一个知识点&#xff0c;那就是浅拷贝和深拷贝&#xff0c;那么就必须知道基本数据类型和引用类型&#xff0c;其实深拷贝和浅拷贝的主要区别就是其在内存中的存储类型不同。 网片来自网络&#xff08;侵删&#xff09; …

C++的浅拷贝与深拷贝

目录 前言 一、区别 二、浅拷贝 1.简单描述 2.代码实例 三.深拷贝 1.简单描述 2.代码实例 四.完整代码 五.运行结果 总结 前言 C中有两种拷贝&#xff1a;深拷贝和浅拷贝 要是想要运用好拷贝函数就必须清楚深拷贝与浅拷贝的区别 一、区别 1 在未定义拷贝构造函数…

拷贝构造(深拷贝、浅拷贝)

一、概念介绍 拷贝构造&#xff1a;拷贝构造函数&#xff0c;又称构造函数&#xff0c;是一种特殊的构造函数&#xff0c;它由编译器调用来完成一些基于同一类的其他对象的构造及初始化。 其唯一的形参必须是引用&#xff0c;但并不限制为const&#xff0c;一般普遍的会加上c…

C++——深拷贝和浅拷贝

1.浅拷贝与深拷贝的区别 浅拷贝&#xff08;默认拷贝函数&#xff09;&#xff1a;将原对象或原数组的引用直接赋给新对象&#xff0c;新数组&#xff0c;新对象/新数组只是原对象的一个引用。 深拷贝&#xff1a;创建一个新的对象和数组&#xff0c;将原对象的各项属性的“值”…

深拷贝和浅拷贝的区别和与原理

一、基本类型和引用类型 string,number,boolean,null,undefined,symbolFunction,Array,Object 基本类型是按值访问的&#xff0c;引用类型是按引用访问 基本类型和引用类型也有人叫原始类型和对象类型&#xff0c;拥有方法的类型和不能拥有方法的类型&#xff0c;可变类型和不…

浅拷贝、深拷贝

深拷贝和浅拷贝 这两个概念是在项目中比较常见的&#xff0c;在很多时候&#xff0c;都会遇到拷贝的问题&#xff0c;我们总是需要将一个对象赋值到另一个对象上&#xff0c;但可能会在改变新赋值对象的时候&#xff0c;忽略掉我是否之后还需要用到原来的对象&#xff0c;那么就…

深拷贝和浅拷贝(copy和deepcopy)详解

深拷贝和浅拷贝&#xff08;copy和deepcopy&#xff09;详解 详细解释存储方式列表的增删改列表修改已有值列表新增一个值列表整体重新赋值 copy与deepcopy的区别不可变类型可变类型 浅拷贝指的是创建一个新对象&#xff0c;其中包含原始对象的引用&#xff08;指针&#xff09…

浅拷贝和深拷贝的区别?

创建Java对象的方式包括new、反射、反序列化、拷贝&#xff0c;那么什么是拷贝呢&#xff1f;浅拷贝和深拷贝又有什么区别呢&#xff1f; 什么是拷贝 拷贝就是为了复用原对象的部分或全部数据&#xff0c;在原对象的基础上通过复制的方式创建一个新的对象。 Object类中有nati…

深拷贝和浅拷贝的区别

首先&#xff0c;明确一点深拷贝和浅拷贝是针对对象属性为对象的&#xff0c;因为基本数据类型在进行赋值操作时&#xff08;也就是拷贝&#xff09;是直接将值赋给了新的变量&#xff0c;也就是该变量是原变量的一个副本&#xff0c;这个时候你修改两者中的任何一个的值都不会…

浅拷贝与深拷贝的区别

浅拷贝与深拷贝 一、数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined&#xff0c;Symbol)和对象数据类型。 基本数据类型的特点&#xff1a;直接存储在栈(stack)中的数据 引用数据类型的特点&#xff1a;存储的是该对象在栈中引用&#xff0c;真实的…

堆、栈和队列

1. 堆 堆是在程序运行时&#xff0c;而不是在程序编译时&#xff0c;申请某个大小的内存空间。即动态分配内存&#xff0c;对其访问和对一般内存的访问没有区别。堆是指程序运行时申请的动态内存&#xff0c;而栈只是指一种使用堆的方法(即先进后出)。 2. 栈&#xff08;stack&…

堆、栈和队列的区别

目录 数据结构中的堆、栈和队列 内存申请中的堆和栈 一个C/C程序占用的内存如下&#xff1a; 申请内存后的响应 申请大小的限制 申请效率的比较 堆和栈中的存储内容 数据结构中的堆、栈和队列 堆&#xff1a;堆是一种经过排序的树形数据结构&#xff0c;每个结点都有…

栈和队列

文章目录 栈栈操作队列队列操作双端队列双端队列操作 栈 栈&#xff08;stack&#xff09;&#xff0c;有些地方称为堆栈&#xff0c;是一种容器&#xff0c;可存入数据元素、访问元素、删除元素&#xff0c;它的特点在于只能允许在容器的一端&#xff08;称为栈顶端指标&…

栈和队列简介

栈和队列简介 栈和队列是两种常用的数据结构&#xff0c;它们的数据是按线性结构存储的&#xff0c;因此&#xff0c;栈和队列也属于线性表。 栈和队列的数据可以存储在一个顺序表里&#xff0c;也可以存储在一个链表里&#xff0c;只要满足线性存储结构就行。只对数据的线性…

栈和队列基本操作

栈和队列 一、栈栈是什么栈的实现栈的基本操作栈类型的定义初始化栈检查栈是否为满入栈出栈获取栈顶元素检测栈是否为空测试函数 完整代码Stack.hStack.cmain.c 二、队列队列是什么队列的实现队列类型的定义申请一个节点初始化队列队尾入队列队头出队列获取队列头部元素获取队列…

C#队列和栈的使用

一、队列 队列是其元素以先进先出&#xff08;Firstin,Firstout,FIFO&#xff09;的方式来处理的集合。先放入队列中的元素会先读取。队列使用System.Collections.Generic命名空间中的泛型类Queue<T>实现。 队列的成员 Count&#xff1a;Count属性返回队列中元素个数。…