对象的浅拷贝与深拷贝

  • 什么是对象的拷贝?

    将一个对象赋值给另外一个对象, 我们称之为对象的拷贝

  • 什么是深拷贝, 什么是浅拷贝?

    我们假设将A对象赋值给B对象

  • 浅拷贝是指, 修改B对象的属性和方法会影响到A对象的属性和方法, 我们称之为浅拷贝

    以下几种情况都属于浅拷贝:

    1、默认情况下对象之间的直接赋值都是浅拷贝

     let A = {
    name: 'zyx',
    age: 20
    }
    let B = A
    console.log(B) // {name: "zyx", age: 20}
    //修改B的 name 属性
    B.name = 'ls'
    //A 也收到影响
    console.log(A) // {name: "ls", age: 20}
    console.log(B) // {name: "ls", age: 20}

    ​ 赋值操作(包括对象作为参数、返回值),不会开辟新的内存空间,他只是赋值了对象的引用.也就是除了B这个名字之外,没有其他的内存开销,修改了A也就影响了B,修改了B,也就影响了A.

    如图所示:

2、如果对象的属性包含了引用数据类型(数组、对象),那么哪怕不是直接赋值操作,而是开辟了一层新的内存空间,也就是说只拷贝了A对象的一层,这仍然属于浅拷贝。

 let A = {
name: 'ls',
age: 20,
hobbies: ['dance','basketball','read'],
dogs:{
name: '大黄',
color: 'yellow'
}
}
let B = {}
//定义一个函数,把A对象的属性复制一份给B
function extend(obj1,obj2){
for(var key in obj1){
obj2[key] = obj1[key]
}
}
extend(A,B)
//修改B对象中的引用类型数据 ,A对象也收到影响
B.dogs.color = 'red'
B.hobbies[0] = 'sing'
console.log(B)
console.log(A)

运行截图如下:修改B对象中的引用类型数据 ,A对象也收到影响,属于浅拷贝

3、ES6中新增的 Object.assign() 也是对象的浅拷贝

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。 Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1); obj1.a.b = 2;
obj2.a.b // 2

上面代码中,源对象obj1a属性的值是一个对象,Object.assign拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。

4、扩展运算符(...)

利用扩展运算符可以在构造字面量对象时,进行克隆或者属性拷贝 ,属于浅拷贝

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

5、Array.prototype.slice()

slice() 方法返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。

  • 深拷贝是指, 修改B对象的属性和方法不会影响到A对象的属性和方法, 我们称之为深拷贝

    以下几种情况都属于深拷贝:

    1、默认情况下一个对象的属性如果是基本数据类型, 那么进行复制(拷贝),都是深拷贝

    如果A对象的属性都是基本数据类型(Number、String等),此时要想深拷贝一份A给B,该怎么做呢,在这种要拷贝的对象A只有基本类型的数据时,只需要在内存中开辟一块空间存储B就行了。

     let A = {
    name: 'zyx',
    age: 20
    }
    let B = {}
    //定义一个函数,把A对象的属性复制一份给B
    function extend(obj1,obj2){
    for(var key in obj1){
    obj2[key] = obj1[key]
    }
    }
    extend(A,B)
    console.log(B) // {name: "zyx", age: 20}
    B.name = 'ls'
    console.log(B) // {name: "ls", age: 20}
    console.log(A) // {name: "zyx", age: 20}

    这样就实现了深拷贝,如下图所示:

2、如果要拷贝的对象本身又包含了引用数据类型,即对象又包含数组或者对象,层层嵌套的情况下,想要实现对象的深拷贝,可以采用递归的方式进行深拷贝。

 let A = {
name: 'ls',
age: 20,
hobbies: ['dance','basketball','read'],
dogs:{
name: '大黄',
color: 'yellow'
}
}
let B = {}
//定义一个函数,把A对象的属性复制一份给B
function extend(obj1,obj2){
for(var key in obj1){
var item = obj1[key]
if(item instanceof Array){
obj2[key] = []
extend(item,obj2[key])
}else if(item instanceof Object){
obj2[key] = {}
extend(item,obj2[key])
}else{
obj2[key] = item
}
}
}
extend(A,B) B.dogs.color = 'red'
B.hobbies[0] = 'sing'
console.log(B)
console.log(A)

运行发现,修改B对象的引用数据类型,不会影响到A对象,完成深拷贝

我们可以对深拷贝的代码进行封装优化

function deepClone(obj){
let cloneObj = {}
for(let key in obj){
if(typeof obj[key] === 'object'){
cloneObj[key] = deepClone(obj[key])
}else{
cloneObj[key] = obj[key]
}
}
return cloneObj
}

3、通过JSON.stringify实现深拷贝

JSON.stringify()是目前前端开发过程中最常用的深拷贝方式,原理是把一个对象序列化成为一个JSON字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON.parse()反序列化将JSON字符串变成一个新的对象。

var obj1 = {
a:1,
b:[1,2,3]
}
var str = JSON.stringify(obj1)
var obj2 = JSON.parse(str)
console.log(obj2); //{a:1,b:[1,2,3]}
obj1.a=2
obj1.b.push(4);
console.log(obj1); //{a:2,b:[1,2,3,4]}
console.log(obj2); //{a:1,b:[1,2,3]}

本文原创,欢迎到我的博客踩踩~ 地址:https://www.cnblogs.com/zyxnb/

最新文章

  1. linux系统下make & make install
  2. Android学习系列(37)--App调试内存泄露之Context篇(下)
  3. 兼容IE的CSS的”引入方式“
  4. angular入门系列教程4
  5. 基于ArcGIS的栅格图像平滑处理(转)
  6. SQL访问EXCEL错误集合
  7. wpf DataGrid CheckBox列全选
  8. CF 121E Lucky Array 【树状数组】
  9. Android三种实现自定义ProgressBar的方式介绍
  10. 2013 多校联合2 D Vases and Flowers (hdu 4614)
  11. iOS 事件处理机制与图像渲染过程
  12. 使用 NuGet 管理项目库
  13. Java线程并发中常见的锁--自旋锁 偏向锁
  14. Java中多线程同步类 CountDownLatch
  15. 第六周PTA作业
  16. django框架配置mysql数据库
  17. XMPP大杂烩
  18. kvm键盘使用
  19. jdk8-Optional类
  20. Mercedes offline programming/coding tips and guides

热门文章

  1. Asp.Net Core 3.0 Kestrel服务器下 高性能 WebSocket Server
  2. [bzoj4571] [loj#2016] [Scoi2016] 美味
  3. 美食家App开发日记2
  4. python+pandas+jupyter notebook 的 hello word
  5. Idea破解至2089年
  6. copy and swap技巧与移动赋值操作符
  7. python多层数组合成一个数组后循环打印出数组内的每一项元素的方法
  8. 解决apt-get安装软件包的时候遇到E: Sub-process /usr/bin/dpkg returned an error code (1)问题
  9. 【WPF学习】第二十五章 日期控件
  10. Spring中的BeanPostProcessor详解