3

本文主要介绍深拷贝和浅拷贝的概念及区别。
我们先从堆和栈说起。
一、堆和栈
堆和栈都是内存中划分出来用来存储的区域。

栈(stack)为自动分配的内存空间,它由系统自动释放;而堆(heap)则是动态分配的内存,大小不定也不会自动释放。

二、数据类型
数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和引用数据类型(Object,Array...)。

基本数据类型的特点:直接存储在栈(stack)中的数据
引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

三、赋值=浅拷贝??

先来说赋值
对于基本数据类型来说,赋值无需多说。基本类型的赋值的两个变量是两个独立相互不影响的变量。
但是引用类型的赋值是传址。只是改变指针的指向,例如,也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。

    var a = {
        name:'weiwei'
    }; 
    var b = a; // 新建一个b对象,地址指向a指向的堆
    a.name='ww';
    console.log(a.name); // 'ww' 
    console.log(b.name); // 'ww' 
    b.age = 22; 
    console.log(b.age);// 22 
    console.log(a.age);// 22

附上图片说明一张(迷之画风)
image.png

该案例说明了引用类型赋值时传的是地址指向,当一个改变时另一个也会被改变。

再来说说浅拷贝
浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据。

let a = {
    id:1,
    age: {name:1}
}
function shallowCopy(src) {
    var dst = {};
    for (var prop in src) {
        if (src.hasOwnProperty(prop)) {
            dst[prop] = src[prop];
        }
    }
    return dst;
}
let b=shallowCopy(a);
b.id=2;//id为第一层属性,改变浅拷贝后的,原来不会改变
console.log(a.id); //1
b.age.name=2;//name为第二层属性,改变浅拷贝后的,原来会改变
console.log(a.age.name); //2

实现浅拷贝的方法
Object.assign()

let a = { age: 1 } 
let b = Object.assign({}, a); 
a.age = 2;
console.log(b.age); // 1

另外我们还可以通过展开运算符...来实现浅拷贝

let a = { age: 1 } 
let b = { ...a } 
a.age = 2  
console.log(b.age) // 1

浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就又回到最开始的话题了,两者享有相同的地址。要解决这个问题,我们就得使用深拷贝了。

四、深拷贝

1.JSON.parse(JSON.stringify())
原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

这种方法虽然可以实现数组或对象深拷贝,但不能处理函数

2.手写递归方法
递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
图片描述

3.函数库lodash
该函数库也有提供_.cloneDeep用来做 Deep Copy
图片描述

后续将不断更新完善,期待您的批评指正!


薇薇
298 声望24 粉丝

路漫漫其修远兮,吾将上下而求索