当前位置:网站首页>js深拷贝和浅拷贝具体使用区别_es6深拷贝和浅拷贝
js深拷贝和浅拷贝具体使用区别_es6深拷贝和浅拷贝
2022-08-04 13:49:00 【全栈程序员站长】
大家好,又见面了,我是你们的朋友全栈君。
一、 “深拷贝” 与 “浅拷贝” 的区别
对于这个问题,可以考虑从深拷贝和浅拷贝的使用或者起源说起,也就是为什么会出现这个问题。
首先了解一些javascript的基本知识。
【1】javascript变量包含两种不同数据类型的值:基本类型和引用类型。
①基本类型值指的是简单的数据段,包括es6里面新增的一共是有6种,具体如下: String、Number、Boolean、Null、Undefined、Symbol ②引用类型值指那些可能由多个值构成的对象,具体如下: Object(Object、Array、Function)
在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。 在操作对象时, 实际上是在操作对象的引用而不是实际的对象。
【2】javascript的变量的存储方式–栈(stack)和堆(heap)
栈:自动分配内存空间,系统自动释放,里面存放的是基本类型的值和引用类型的地址
堆:动态分配的内存,大小不定,也不会自动释放。里面存放引用类型的值。
【3】javascript值传递与址传递
基本类型与引用类型最大的区别实际就是传值与传址的区别
值传递:基本类型采用的是值传递。
let a = 10; // 定义一个变量a并赋值为10
let b = a; // 将a的值10赋值给b (a、b都是基本类型,值传递)
b++; // b自加
console.log(a, b) // 10, 11复制代码
址传递:引用类型则是地址传递,将存放在栈内存中的地址赋值给接收的变量。
let a = ['a', 'b', 'c']; // 定义一个数组a并赋值
let b = a; // 数组是引用类型,采用地址传递,将a的地址赋值给b
b.push('d'); // 给b数组增加一个'd'元素
console.log(a) // ['a', 'b', 'c', 'd']
console.log(b) // ['a', 'b', 'c', 'd']复制代码
分析:由于a和b都是引用类型,采用的是址传递,即a将地址传递给b,那么a和b必然指向同一个地址(引用类型的地址存放在栈内存中),而这个地址都指向了堆内存中引用类型的值。当b改变了这个值的同时,因为a的地址也指向了这个值,故a的值也跟着变化。 举例:就好比是a租了一间房,将房间的地址给了b,b通过地址找到了房间,那么b对房间做的任何改变(添加了一些绿色植物)对a来说肯定同样是可见的。 那么如何解决上面出现的问题,就是使用浅拷贝或者深拷贝了。 JS的基本类型不存在浅拷贝还是深拷贝的问题,主要是针对于引用类型
【4】浅拷贝和深拷贝区别总结
字面意思:
浅拷贝—拷贝的级别浅。
深拷贝—拷贝级别更深。
具体:
浅拷贝—浅拷贝是指复制对象的时候,只对第一层键值对进行独立的复制,如果对象内还有对象,则只能复制嵌套对象的地址
深拷贝—深拷贝是指复制对象的时候完全的拷贝一份对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。其实只要递归下去,把那些属性的值仍然是对象的再次进入对象内部一 一进行复制即可。
浅拷贝案例
浅拷贝解决就是先设置一个新的对象obj2,通过遍历的方式将obj1对象的值一 一赋值给obj2对象。
// 数组的浅拷贝
let arr1 = [1, 2, 3]
let arr2 = []
for (let i in arr1) {
arr2[i] = arr1[i]
}
arr2.push(4)
console.log(arr1) // [1, 2, 3]
console.log(arr2) // [1, 2, 3, 4]
// 对象的浅拷贝
let obj1 = {
a: '1',
b: '2',
c: '3'
}
let obj2 = {}
for (let i in obj1) {
obj2[i] = obj1[i]
}
obj2.d = '4'
console.log(obj1) // {a: "1", b: "2", c: "3"}
console.log(obj2) // {a: "1", b: "2", c: "3", d: "4"}
// 浅拷贝函数封装
function shallowCopy(obj1, obj2) {
for(var key in obj1) {
obj2[key] = obj1[key]
}
}
但上面代码只能实现一层的拷贝,无法进行深层次的拷贝,封装函数再次通过对象数组嵌套测试如下:
// 浅拷贝函数封装
function shallowCopy(obj1, obj2) {
for(var key in obj1) {
obj2[key] = obj1[key]
}
}
// 对象的浅拷贝
let obj1 = {
a: '1',
b: '2',
c: {
name: 'Demi'
}
}
let obj2 = {}
shallowCopy(obj1, obj2) //将obj1的数据拷贝到obj2
obj2.c.name = 'dingFY'
console.log(obj1) // {a: "1", b: "2", c: {name: 'dingFY'}}
console.log(obj2) // {a: "1", b: "2", c: {name: 'dingFY'}}复制代码
结果证明,如果对象内还有对象,则只能复制嵌套对象的地址,无法进行深层次的拷贝,当改变obj2嵌套对象c的值后,obj1嵌套对象c的值也跟着变了
这个时候我们可以使用深拷贝来完成,所谓深拷贝,就是能够实现真正意义上的数组和对象的拷贝,我们通过递归调用浅拷贝的方式实现。
深拷贝案例
// 深拷贝函数封装
function deepCopy(obj) {
// 根据obj的类型判断是新建一个数组还是对象
let newObj = Array.isArray(obj)? [] : {};
// 判断传入的obj存在,且类型为对象
if (obj && typeof obj === 'object') {
for(key in obj) {
// 如果obj的子元素是对象,则进行递归操作
if(obj[key] && typeof obj[key] ==='object') {
newObj[key] = deepCopy(obj[key])
} else {
// // 如果obj的子元素不是对象,则直接赋值
newObj[key] = obj[key]
}
}
}
return newObj // 返回新对象
}
// 对象的深拷贝
let obj1 = {
a: '1',
b: '2',
c: {
name: 'Demi'
}
}
let obj2 = deepCopy(obj1) //将obj1的数据拷贝到obj2
obj2.c.name = 'dingFY'
console.log(obj1) // {a: "1", b: "2", c: {name: 'Demi'}}
console.log(obj2) // {a: "1", b: "2", c: {name: 'dingFY'}}复制代码
结果证明上面的代码可以实现深层次的克隆。
数组的浅拷贝
如果是数组,我们可以利用数组的一些方法比如:slice、concat 返回一个新数组的特性来实现拷贝。
【1】Array.concat()
let arr = ['one', 'two', 'three'];
let newArr = arr.concat();
newArr.push('four')
console.log(arr) // ["one", "two", "three"]
console.log(newArr) // ["one", "two", "three", "four"]复制代码
【2】Array.slice()
let arr = ['one', 'two', 'three'];
let newArr = arr.slice();
newArr.push('four')
console.log(arr) // ["one", "two", "three"]
console.log(newArr) // ["one", "two", "three", "four"]复制代码
数组的深拷贝
这里介绍一个技巧,不仅适用于数组还适用于对象!不过存在一个问题,就是不能拷贝函数
let arr = {
a: 'one',
b: 'two',
c: {
name: 'Demi'
}
};
let newArr = JSON.parse( JSON.stringify(arr) );
newArr.c.name = 'dingFY'
console.log(arr); // {a: "one", b: "two", c: {name: 'Demi'}}
console.log(newArr); // {a: "one", b: "two", c: {name: 'dingFY'}}
// 测试函数能否复制
let arr = {
a: 'one',
b: ()=>{
console.log('test')
}
};
let newArr = JSON.parse( JSON.stringify(arr) );
console.log(arr); // {a: "one", b: ()=>{console.log('test')}}
console.log(newArr); // {a: "one"} // 函数没有复制成功复制代码
对象的浅拷贝
Object.assign()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝
let arr = {
a: 'one',
b: 'two',
c: 'three'
};
let newArr = Object.assign({}, arr)
newArr.d = 'four'
console.log(arr); // {a: "one", b: "two", c: "three"}
console.log(newArr); // {a: "one", b: "two", c: "three", d: "four"}复制代码
浅拷贝封装方法
原理:遍历对象,然后把属性和属性值都放在一个新的对象
let shallowCopy = function (obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;
// 根据obj的类型判断是新建一个数组还是对象
let newObj = obj instanceof Array ? [] : {};
// 遍历obj,并且判断是obj的属性才拷贝
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
深拷贝封装方法
原理:我们在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数就好了
let deepCopy = function (obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;
// 根据obj的类型判断是新建一个数组还是对象
let newObj = obj instanceof Array ? [] : {};
// 遍历obj,并且判断是obj的属性才拷贝
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 如果obj的子属性是对象,则进行递归操作,否则直接赋值
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/106856.html原文链接:https://javaforall.cn
边栏推荐
猜你喜欢
中大型商业银行堡垒机升级改造就用行云管家!必看!
封装、继承、多态的联合使用实现不同等级学生分数信息的统计
zabbix自定义图形
将 Sentinel 熔断限流规则持久化到 Nacos 配置中心
Programmer Qixi Gift - How to quickly build an exclusive chat room for your girlfriend in 30 minutes
PMP每日一练 | 考试不迷路-8.4(包含敏捷+多选)
This article sorts out the development of the main models of NLP
"C pitfalls and pitfalls" reading summary
Haproxy搭建web群集
Fuse bit of AVR study notes
随机推荐
大势所趋之下的nft拍卖,未来艺术品的新赋能
JSX use
相似文本聚类与调参
LeetCode 1403 Minimum subsequence in non-increasing order [greedy] HERODING's LeetCode road
博途1200/1500PLC斜坡指令RAMP(带暂停功能)
阿里老鸟终于把测试用例怎么写说的明明白白了,小鸟必看
开放麒麟 openKylin 版本规划敲定:10 月发布 0.9 版并开启公测,12 月发布 1.0 版
SMART S7-200PLC串行自由口通讯(耐压测试仪)
文字编码 - XML 教程
从理论到实践:MySQL性能优化和高可用架构,一次讲清
数据库的基本概念
七夕邂逅爱,那人一定在
Fuse bit of AVR study notes
企业应当实施的5个云安全管理策略
荧光磷脂PEG衍生物之一磷脂-聚乙二醇-荧光素,Fluorescein-PEG-DSPE
漏洞复现 - - - Alibaba Nacos权限认证绕过
人像分割技术解析与应用
RK1126编译gdb 板子上gdb调试程序
State security organs conduct criminal arrest and summons review on Yang Zhiyuan, a suspect suspected of endangering national security
《社会企业开展应聘文职人员培训规范》团体标准在新华书店上架