js:浅拷贝与深拷贝

196 阅读3分钟

一、浅拷贝与深拷贝官方含义

🔸浅拷贝: 拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这个内存空间的所有指针需要重新定义,不然会造成野指针错误。

🔸深拷贝: 一个具名的Handle,也就是我们所说的声明(如变量)和一个内部(不具名)的对象,也就是具名Handle的内部对象。它在MangedHeap(托管堆)中分配,一般由新增引用对象的New方法是进行创建。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响

二、浅拷贝与深拷贝自身理解

🔸数据类型: JS分两种数据类型

1、基本数据类型:Number、String、Boolean、Null、Undefined、Symbol(ES6),这些类型可以直接操作保存在变量中的实际值。

2、引用数据类型:Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)

(深拷贝针对于的数据类型引用数据类型:如数组、对象)

🔸关于拷贝

基本数据类型,a的value值存在栈内存中
    let a = 1;
拷贝复制一份,栈内存打开一个新的内存,存储b的值
    let b = a;
    console.log(a,b); 
此时结果:1 1。
当我去改变a的值:
    a = 2;
    console.log(a,b); 
此时结果:2 1。
可以看出,b拷贝出来后。不再受a的影响,因为b已经开辟了自己的内存空间,a和b各自独立。

🔸关于浅拷贝与深拷贝

💗 浅拷贝

首先我们创建一个a数组
let a = [0,1,2,3,4]

复制a到b,从图中看出,当拷贝的时候,b只是复制了a的堆地址,他们公用一块堆内存。
这就是所谓的浅拷贝。
我们从代码来看
let b = a;
a[0] = 1;
console.log(a,b)
此时结果:

可以看出,当a里面的值改变时,b里面的值也会相应着改变,这就是浅拷贝。

💗 深拷贝

如何实现深拷贝呢?答案:在堆内存里创建多一个新的内存来存放b的值。

function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);
此时结果:

可以看出,当a里面的值改变时,b里面的值不会再跟随着改变,这就是深拷贝。
⚠️⚠️ 强烈注意:js中:concat 和 slice不是真正的深拷贝,他们只会拷贝第一层,深层不会再继续拷贝下去。
let a=[0,1,[2,3],4],
b=a.slice();
a[0]=1;
a[2][0]=1;
console.log(a,b);
此时结果:

🔸开发当中常用的深拷贝方法

💗 JSON对象的parse和stringify

function deepClone(obj){
    let _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
    return objClone
}    
let a=[0,1,[2,3],4],
    b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
此时结果:

💗 JQ的extend方法

$.extend( [ deep ], target, object1 [, objectN ] )

deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝

target **** Object类型 目标对象,其他对象的成员属性将被附加到该对象上。

object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。

let a=[0,1,[2,3],4],
    b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

🔸深拷贝的作用

深拷贝可以让我们更安全的操作数据,不会破坏原来的数据。