【JS】浅谈浅拷贝与深拷贝


前言

我们对数组或者对象进行操作的时候,有时并不想操作原始对象,就会将对象或数组复制出新一份,在新的一份中进行操作。

深拷贝与浅拷贝是常用于对象或数组进行复制。
在这里插入图片描述


一、浅拷贝?

1.1是什么?

浅拷贝是指复制对象时,只复制对象的引用,而不复制引用指向的对象本身。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存中的地址。

先用一张图理解这句话
在这里插入图片描述
当B从A中复制一份时,他们在内存地址中指向仍旧是同一个,如果此时A改变了某些值,因为B和A指向是相同的,B此时也会跟着改变。也就是说B只是复制A在内存地址的引用,并没复制A的本身。

1.2做什么?

浅拷贝它复制了原始对象中的所有字段到新的对象中,对于值类型,复制操作不会对原对象的字段值有任何影响;

对于引用类型,新的对象对引用类型中的字段赋值等操作,会对原引用类型对象中的字段进行更改。

浅拷贝经常用于在不需要深度复制对象的情况下快速复制对象。

1.3为什么使用?

  • 内存使用优化:浅拷贝允许多个对象共享相同的数据区,这样可以显著减少内存的消耗。特别是当处理大型数据结构。
  • 性能提升:减少拷贝的次数,从而提升程序的运行效率。
  • 特定需求:只要复制对象的顶层数据,而不是对象的所有层次。

1.4实现方式?

  • 扩展运算符(…)
const originalArray = [1, 2, [3, 4]];  
const shallowCopyArray = [...originalArray]; 
  • Object.assign()
const originalArray = { a: 1, b: { c: 2 } };  
const shallowCopyArray = Object.assign({},originalArray); 
  • Array.prototype.slice(), Array.prototype.concat()
const originalArray = [1, 2, [3, 4]];  
const shallowCopyArray = originalArray.slice(); 

const shallowCopyArray = originalArray.concat(); 

1.5 应用场景?

  • 组件间传值:子组件只是读取这些数据而不进行修改
  • 计算属性或方法中的临时变量:基于当前组件的状态或传入的参数创建一些临时变量。如果这些临时变量只是简单地读取状态或参数的值,而不进行修改

二、深拷贝?

2.1是什么?

深拷贝是指复制对象时,不仅复制对象本身,还复制对象所引用的所有对象,直到所有引用的对象都被完全复制。

先用一张图理解这句话
在这里插入图片描述
当B从A中复制一份时,不仅新创建了B对象,还创造一块新的内存,此时B和A在内存中的指向不再是同一块。如果A改变了,B不会受影响。

2.2做什么?

深拷贝独立创建新的对象和开辟一块新的内存,对于值和引用类型,复制操作不会对原对象的字段值有任何影响;

深拷贝经常用于不影响原对象情况下复制新对象。深拷贝相对于浅拷贝来说,更加复杂耗时,但可以确保数据的安全性。

2.3为什么使用?

  • 避免数据冲突:使用深拷贝可以确保新对象与原始对象完全独立,对其中一个对象的修改不会影响另一个。
  • 确保数据完整:深拷贝可以复制对象的所有层级,从而确保整个对象的完整性。
  • 特定需求:不影响原始数据操作。

2.4实现方式?

  • JSON.stringify()
const obj2=JSON.parse(JSON.stringify(obj1));

但是这种方式存在弊端,会忽略undefined、symbol和函数

const obj = {
    name: 'A',
    name1: undefined,
    name3: function() {},
    name4:  Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}
  • 循环递归

  • _.cloneDeep()
const _ = require('lodash');
const obj = {
    a: 1,
};
const obj1 = _.cloneDeep(obj);

2.5应用场景?

  • 组件间数据传递:子组件对数据的修改不会影响到父组件或其他兄弟组件。

  • Vuex状态管理:在Vuex中,状态是响应式的,当状态改变时,视图也会自动更新。通过深拷贝,我们可以创建一个状态的独立副本,在组件内部进行修改,而不会触发全局状态的更新。

  • 避免直接修改props:需要基于props的数据进行修改,可以先使用深拷贝创建一个副本,然后在副本上进行修改。

三、区别

  • 共同点:
    • 都是复制数据
  • 不同点:
    • 浅拷贝是复制内存中的地址,拷贝前后的对象,因为引用类型共享了同一块内存,修改会相互影响。基本类型值不变,引用类型会改变
    • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址。基本类型和引用类型不改变

总结

  • 浅拷贝
    • 引用同一块内存,会影响原数据
    • 基本类型值不变,引用类型会改变
    • 实现方式:… , Object.assign() , slice(),concat()
  • 深拷贝
    • 新开辟内存,不影响原数据
    • 基本类型和引用类型不改变
    • 实现方式:循环递归 , JSON.stringify() , loadsh库中_.cloneDeep()
      在这里插入图片描述
  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值