Skip to content

Latest commit

 

History

History
101 lines (89 loc) · 3.16 KB

深浅拷贝.md

File metadata and controls

101 lines (89 loc) · 3.16 KB

JS中的深拷贝与浅拷贝

说到深浅拷贝的时候就不得不说一下JS中的变量类型了:

  • 基本类型: undefinednullbooleannumberstring, 按值存放在栈内存中的简单数据段, 可以直接访问.

  • 引用类型: 存放在堆内存中的对象, 变量保存的是一个指向存放数据位置的指针. 访问引用类型(object, array)的值时, 首先从栈中获取到存放该数据位置的指针, 然后再从堆中取得数据.

  • 浅拷贝: 浅拷贝是拷贝引用, 拷贝后的引用都是指向同一个存放数据位置的指针, 无论操作哪一个都是在操作指向在堆中的那一个数据, 所以双方都会有影响.

  • 深拷贝: 在堆中重新分配内存, 将源对象的各个属性复制进去. 对拷贝对象和源对象各自操作互不影响.

浅拷贝

浅拷贝分两种情况, 拷贝源对象的引用和源对象拷贝实例, 但其属性拷贝引用. 拷贝源的引用 eg:

let obj1 = {
    a: 1
};
let obj2 = obj1;

console.log(obj1 === obj2); // true

obj1.a = 2;

console.log(obj2.a); // 2

源对象拷贝实例, 其属性对象拷贝引用 外层源对象是拷贝实例, 但是如果源对象的属性元素为复杂数据类型时, 内层元素拷贝引用. 对源对象操作时不影响拷贝对象. 但对其属性操作时, 会改变拷贝对象属性的值. 常用方法: Array.prototype.slice(), Array.prototype.concat(), jQuery$.extend({}, obj), Object.assign()等. eg:

let obj1 = {
    a: 1,
    b: [1, 2, 3],
    c: {
        c1: 1
    }
};

let obj2 = Object.assign({}, obj1);
obj2.a = 2;
obj2.b[0] = 2;
obj2.c.c1 = 10
console.log(obj1);
/**
输出结果:
{
    a: 1, 
    b: [2, 2, 3],
    c: {
        c1: 10
    }
}
**/

这上面的例子中obj1为源对象, obj2为拷贝对象. 拷贝后修改拷贝对象的属性a没有影响到源对象, 修改拷贝对象的复杂数据类型属性b, c后影响到源对象.

深拷贝

深拷贝过后, 源对象、拷贝对象包括其内部元素(包括复杂类型元素)都不互相干扰. 常见方法有JSON.parse(JSON.stringify(obj)), jQuery$.extend(true, {}, obj), lodash_.cloneDeep_clone(value, true). eg:

let obj1 = {
    a: 1,
    b: [1, 2, 3],
    c: {
        c1: 1
    }
};

let obj2 = JSON.parse(JSON.stringify(obj1));

obj2.a = 2;
obj2.b[0] = 2;
obj2.c.c1 = 10
console.log(obj1);
/**
输出结果:
{
    a: 1, 
    b: [1, 2, 3],
    c: {
        c1: 1
    }
}
**/

最后输出源对象(obj1) 得到结果是源对象未变化. 深拷贝就是增加一个指针(栈内存)申请一个新的堆内存, 并让这个指针指向这个堆内存. 当我们需要复制源对象而又不能修改源对象的时候, 深拷贝就是你想要的.

那么是时候自己实现一个深拷贝方法了:

function deepclone(sObj, cObj) {
    cObj = cObj || (Array.isArray(sObj) ? [] : {});

    for(let i in sObj) {
        if(typeof sObj[i] === 'object') {
            cObj[i] = Array.isArray(sObj[i]) ? [] : {};
            deepclone(sObj[i], cObj[i])
        } else {
            cObj[i] = sObj[i]
        }
    };

    return cObj;
}