JavaScript深浅拷贝区别

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。

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

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
JavaScript深浅拷贝区别_第1张图片

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。

假设B复制了A,修改A的时候,看B是否发生变化:

如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)

如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)

浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,

深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,

使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。

浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。

深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。

浅拷贝实例:

 //此递归方法不包含数组对象
    var obj = { a: 1, arr: [2, 3] };
    var shallowObj = shallowCopy(obj);

    function shallowCopy(src) {
        var newobj = {};
        for (var prop in src) {
            if (src.hasOwnProperty(prop)) {
                newobj[prop] = src[prop];
            }
        }
        return newobj;
    }

因为浅复制只会将对象的各个属性进行复制,并不会进行递归复制,而JavaScript存储对象是存地址的,所以浅复制会导致Obj.arr和shallowObj.arr指向同一块内存地址:
JavaScript深浅拷贝区别_第2张图片
导致的结果就是:

shallowObj.arr[1] = 5;
console.log(obj.arr[1]); //5

深拷贝实例:

 var obj = {
        a: 1,
        arr: [1, 2],
        nation: '中国',
        birthplaces: ['北京', '上海', '广州']
    };
    var obj2 = { name: '杨' };
    obj2 = deepCopy(obj, obj2);
    console.log(obj2);
    //深复制,要想达到深复制就需要用递归
    function deepCopy(o, c) {
        var c = c || {};
        for (var i in o) {
            if (typeof o[i] === 'object') {
                if (o[i].constructor === Array) {
                    //这是数组
                    c[i] = [];
                } else {
                    //这是对象
                    c[i] = {};
                }
                deepCopy(o[i], c[i]);
            } else {
                c[i] = o[i];
            }
        }
        return c;
    }

而深复制则不同,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在obj和shallowObj的arr属性指向同一个对象的问题。
JavaScript深浅拷贝区别_第3张图片
这样obj1和obj2分别拥有不同的内存地址,两边的值改变互不影响。

浅拷贝实现:

    var a = [1, 2, 3, 4, 5];
    var b = a;
    a[0] = 2
    console.log(a);
    console.log(b);

//因为b浅拷贝a, ab指向同一个内存地址(堆内存中存的值)
//b会随着a的变化而变化
//[2, 2, 3, 4, 5]
//[2, 2, 3, 4, 5]

JavaScript深浅拷贝区别_第4张图片

深拷贝实现:

function deepClone(obj) {
        var newObj = obj instanceof Array ? [] : {};
        if (typeof obj !== 'object') {
            return obj;
        } else {
            for (var i in obj) {
                newObj[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
            }
        }
        return newObj;
    }

    var a = [1, 2, 4, 6, "a", "12", [1, 2]];
    var b = deepClone(a);
    a[3] = 7;
    console.log(a);
    console.log(b);
    
    //b对象并没有因为a对象的改变而改变,因为b深拷贝a
      [ 1, 2, 4, 7, 'a', '12', [ 1, 2 ] ]
      [ 1, 2, 4, 6, 'a', '12', [ 1, 2 ] ]

JavaScript深浅拷贝区别_第5张图片

你可能感兴趣的:(javascript)