浅谈深拷贝和浅拷贝(js)

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明是浅拷贝,如果B没变,那就是深拷贝。深入点来说,就是B复制了A,如果B复制的是A的引用,那就是浅拷贝,如果B复制的是A的本体,那就是深拷贝。在深入了解深拷贝和浅拷贝之前,我们先得了解堆栈和数据类型。

一.堆栈和数据类型

在js中,数据类型分为两种,基本类型和引用类型。基本类型指的是简单的数据段,而引用类型指的是那些可能由多个值构成的对象。js中有五种基本数据类型number,string,boolean,null,undefined,他们的值被以键值对的形式保存在栈中。

引用类型只有object一种。但js中除了基本数据类型,万物皆对象,数组,函数,对象都是object类型,甚至null也被认为是一个空对象,使用typeof检测时返回object。与基本类型不同的是,引用类型的值被保存在堆内存中,对象的引用被保存在栈内存中,而且我们不可以直接访问堆内存,只能访问栈内存。所以我们操作引用类型时实际操作的是对象的引用。

现在我们来看文章开头那句话,浅拷贝是拷贝了对象的引用,所以基本数据类型是不存在深浅拷贝的。当 a=1,b=a时,栈内存会新开辟一个内存,例如这样:

深拷贝与浅拷贝出现的根源就在于引用数据类型。当我们定义a=[0,1,2,3,4],b=a时,其实复制的是a的引用地址,而并非堆里面的值。因为指向了相同的地址,所以当我们更改a时b会改变,更改b时a也会改变,这就是浅拷贝。

但很多时候我们并不希望a和b直接互相影响,这时就需要想下图这样,单独为b也开辟一块堆内存,这就用到了深拷贝。

js并没有什么能帮助我们直接进行深拷贝的方法,想要实现深拷贝需要自己写一个方法。下面就是一个标准的一个深拷贝的函数。

function deepCopy(obj){
    let objCopy = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objCopy[key] = deepCopy(obj[key]);
                }else{
                    //如果不是,简单复制
                    objCopy[key] = obj[key];
                }
            }
        }
    }
    return objCopy;
}    
let a=[1,2,3,4],
    b=deepCopy(a);
a[0]=2;
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方法也可以完成深拷贝,其底层也是封装了一个深拷贝函数,这里就不再多说。

猜你喜欢

转载自blog.csdn.net/qq_41635167/article/details/82943223